# Brücke Layout ↔ E-Planung über `*_positionsdraw.json` Stand 2026-10-15. Erst Machbarkeitsprüfung, inzwischen umgesetzt als `lib/e_planning.py` (Regeln `cfg/e_planning.ini`, Aufruf `bin/e_planning.bat`, `scl_skeleton --eplan`); Bedienung in `doc/Python_Scripts.md` §5c, Stand der Umsetzung unten. Am 2026-10-15 mit dem neuen Mubea-Datensatz in `data/Mubea/` (TIA-Import + Positionsdatei) nachgeprüft; Ergebnisse unter "Nachprüfung 2026-10-15". ## Problem Das Kapitel "Daten" in `doc/Klassenhierarchie.md` zeigt: das Hardwarelayout (CSV) liefert die **Struktur** (welche TROs, welche Separatoren/Weichen, wer mit wem), die E-Planung die **Namen und Adressen** (`BG…`, `MB…`, `MA…`, `FC…`). Die EA-Liste allein kennt aber keine Topologie. Es fehlt die Zuordnung **Layout-Bauteil (CSV-`TeileId`) → Betriebsmittelkennzeichen (BMK)**. ## Idee Die E-Planung wird als Layer über der Hardwareplanung gezeichnet: Sensor- und Aktorsymbole liegen in der Zeichnung neben dem Bauteil, zu dem sie gehören. Das Kabellängen-Tool (`C:\10-Develop\gitrepos\kabellaengen`, `lib/getpositions.py`) schreibt diese Symbole mit Position und Attributen nach `_positionsdraw.json`. Damit ist die Brücke eine **räumliche Zuordnung**: E-Symbol → nächstes Layout-Bauteil passender Art. ## Datenquelle `*_positionsdraw.json` | Schlüssel | Inhalt | Nutzen für sps_skel | |---|---|---| | `sensors` | je BMK (`BG0642@UNKNOWN`): `pos` [x, y], `VERW` (Verwendung), `BEZEICHNUNG` (Klartext), `BESCHR`, `ARTINR`, `KENNZEICHNUNG` (`=A1+UH01-KF107`) | Hauptquelle: Sensoren/Ventile/Motoren im Feld | | `schaltschrank_elemente` | Elemente im Schrank (Motorschutz `FC…`, Taster, Leuchten, `QA…`) mit `VERW`, `BEZEICHNUNG`, `KENNZEICHNUNG`, ohne Feldposition | Motorschutz ↔ Motor, Bedienelemente | | `mappings` | Steuerung → Liste ihrer BMK (`UH01: [...]`) | Steuerungsaufteilung, Nummernkreis | | `racks`, `distributors`, `tunnels` | Kabeltrassen, Verteiler | für sps_skel ohne Belang | | `double_ids`, `warnings` | doppelte BMK, fehlende Attribute | Qualitätsprüfung der E-Daten | Die Erdungs-Beispiele (`PR500501_…_Erdung_…`, `ST500652_…`) enthalten nur Potentialausgleich (`POT…`) und taugen nicht für die Brücke. Brauchbar sind Dateien mit `BG`/`MB`/`MA`: `Mubea_positionsdraw.json` (158 Feld-BMK, davon 157 in `mappings` unter UH01 — `BG0514` hat eine leere `KENNZEICHNUNG`), `ST500592_ILS_positionsdraw.json` (~3100), `ST500592_10_5-10_Omniflo_…` (~900), `ST-Fortna_positions_.json` (mit 38 Scannern `BX`). `*_positionsconv.json` und `*_positionsdraw.json` sind bei Mubea byte-gleich; eine von beiden genügt. ## Datenquelle TIA-Import `*_TIA.xlsx` Die zweite nötige Quelle. Blatt **PLC Tags**: je Signal Name (`BG0542`), Absolutadresse (`%E…`/`%A…`), Kommentar. Blatt **Constants**: je Signal eine Index-Konstante `cIn`/`cOut` (laufender Index, **nicht** aus der Adresse berechenbar). | Nutzen | Warum | |---|---| | SCL übersetzbar | Sensoren stehen im SCL als `"DB_Inputs".Sensors["cInBG…"]`, Ventile als `"MB…"`; beides muss im TIA-Projekt existieren — der TIA-Import liefert genau diese Tags und Konstanten | | Prüfliste | jeder Name im erzeugten SCL muss im TIA-Import stehen | | `FB_CallSensors`, Größe `DB_Inputs` | alle `cIn…`-Konstanten mit Wert (noch nicht generiert) | | Schrank- und Antriebssignale | `SF…` (Taster, Not-Halt), `PF…` (Leuchten), `MA…`/`FC…` (Motor/Motorschutz), `GF…` (Geber), `BP…`, `DI…` | Mubea: 237 Tags (105 BG, 64 MB, 26 SF, 17 PF, 11 MA, 11 FC, je 1 BP/DI/GF) und 237 Konstanten (144 `cIn`, 93 `cOut`). Alle 158 Feld-BMK und 80 von 81 Schrankelementen (fehlt: `QA7000`) der Positionsdatei stehen im TIA-Import, die Kommentare sind 1:1 gleich der `BEZEICHNUNG`. **Nicht nötig** (Mubea): `*_EA.xlsx` (dieselben 237 Signale, nur Adresse und Kommentar, keine Namen), `*_WSCAD.xlsx` (zusätzlich nur die E/A-Baugruppe je Kanal, die `KENNZEICHNUNG` der Positionsdatei schon trägt, und 259 freie Kanäle), `*_BOM.xlsx`, `*_cables.*`, `*_todraw.json`, `*_errors.json` (Kabel, Stückliste, Trassen; die Qualitätswarnungen stehen auch in der Positionsdatei). Eingaben für die Brücke also: **CSV + TIA-Import + eine Positionsdatei**. ## Test an Mubea Eingaben: `data/mubea.csv` (Layout, 38 Separatoren) und `kabellaengen/work/Mubea_positionsdraw.json` (E-Planung, alter Stand). Die Zahlen in diesem Abschnitt stammen aus der ersten Untersuchung (Umkreis 700 mm, ohne Regeln); das Ergebnis der Umsetzung und die Nachprüfung mit dem neuen Stand `data/Mubea/Mubea_positionsdraw.json` stehen unten. ### 1. Lagebezug Die Ermittlung aus `lib/dxf_registration.py` (`derive_transform`) funktioniert unverändert, wenn man die E-Symbole mit `VERW` `SEP`/`IN SEP` als Rolle "Separator" einsetzt: ```text mubea.csv <- Mubea_positionsdraw.json: dx +50613.6 mm, dy +8555.8 mm, Drehung 0 26/38 Separatoren im Toleranzband ``` Das entspricht dem schon gespeicherten Bezug `mubea.csv|500573_60_1.dxf` (dx +50833.7, dy +8414.5) bis auf ~250 mm: diese (alte) E-Zeichnung lag im selben Koordinatensystem wie die Layoutzeichnung. Zum Prüfen genügt also der bestehende Mechanismus; als Schlüssel in `cfg/dxf_registration.json` dient `|`. Das gilt **nicht allgemein**: der neue Stand in `data/Mubea/` liegt in einem anderen Koordinatensystem (dx −151.4, dy −696.6, siehe "Nachprüfung 2026-10-15"). Der Lagebezug ist je Datei neu zu ermitteln, nicht von der Layoutzeichnung zu übernehmen. ### 2. Was sich zuordnen lässt | E-Symbol (`VERW`) | Layout-Partner | Abstand | Ergebnis | |---|---|---|---| | `IN SEP` (BG, Sensor im Separator) | Separator | **0–1 mm** im Pin-Speicher (20/20), sonst 200–500 mm | Anker: das Symbol sitzt auf dem Separator | | `SEP` (MB, Stopperventil) | Separator | konstant **~270 mm** daneben | eindeutig über Nummernregel (unten), nicht über Abstand | | `AE ABZWEIG` (MB, Ausschleusventil) | Ausschleuselement | konstant **1414 mm** (20/20, Versatz (−1405, −159)) | eindeutig, wenn der Versatz je Symbolart bekannt ist | | `STAU_REF-LT` (BG, Stausensor) | Ausschleuselement | konstant **1391 mm** (20/20) | wie oben | | `ABZWEIG-K104` (MB, Weiche) | Weiche | 783 mm | eindeutig (nur eine Weiche) | | `BANDBRUCH`, `KETTENBRUCH`, `ÜBERGABE`/`ÜBERNAHME`, `SYNC P1..4`, `ZAPPLER` | Kreisel/Strecke/Station | uneinheitlich, teils > 50 m (Symbol an Konvejoren außerhalb des CSV-Ausschnitts) | nicht über Abstand, nur über `BEZEICHNUNG` | Nebeneinander liegende Separatoren (Pin-Speicher, Raster 800 mm) machen den Abstand allein mehrdeutig: das MB von Strecke n liegt 270 mm von Separator n und 530 mm von Separator n+1. Eindeutig wird es erst mit der Nummernregel. ### 3. Nummernregel der E-Planung Ventil = Sensor + 1, gleiche Funktionsgruppe: | Paar | Treffer (von 58 MB) | |---|---| | `MB(n)` `SEP` ↔ `BG(n−1)` `IN SEP` (z. B. BG0642 / MB0643) | 31 | | `MB(n)` `AE ABZWEIG` ↔ `BG(n−1)` `STAU_REF-LT` (z. B. BG0542 / MB0543) | 21 | | sonstige Paare (`VEREINZ(CP)`, `STOPPER (CP)`, `AE ABZW.`) | 3 | | ohne BG-Partner | 3 | Damit reicht es, den **Sensor** räumlich zuzuordnen (der `IN SEP` liegt auf dem Separator); das Ventil folgt aus der Nummer. Die SCL-Referenzen zeigen dasselbe Muster (`stSenInSep := …["cInBG3242"]`, `xOutStopper1 => "MB3242"`) — dort sogar mit gleicher Nummer; die Regel ist also projektabhängig und gehört in eine Konfiguration, nicht in den Code. Gleiches gilt für Motor ↔ Motorschutz: `MA0200` "PIN CONVEYOR#100" ↔ `FC0200` "MOTORSCHUTZ CONVEYER #100" (gleiche Nummer, `schaltschrank_elemente`), wie in der SCL `xOutVarioMotor => "MA0145"`, `xInMotorProtection := "FC0145"`. ### 4. Was nicht passt 12 von 38 Layout-Separatoren (vor allem an den Kreiseln K0102/K0104/K0105) haben im Umkreis von 700 mm kein `IN SEP`/`SEP`; umgekehrt liegen mehrere `IN SEP` des Kreisels K0102 neben Aus-/Einschleuselementen statt neben einem Separator. Vermutlich ist die CSV (aus `500573_60_1.dxf`) ein anderer Planungsstand als die E-Zeichnung `Mubea.dxf` des Kabellängen-Tools, oder Kreisel-Separatoren sind im CSV anders modelliert. Das muss mit zueinander passenden Ständen geprüft werden, bevor man eine Quote angibt. `Mubea_positionsdraw.json` enthält **keine Scanner** (`BX`). Für Scanner-Zuordnung ist ein anderes Projekt nötig (`ST-Fortna_positions_.json`, `ILS-Baugruppe`). ## Was die Brücke für das Kapitel "Daten" liefert | SCL-Datum | aus `positionsdraw.json` | Regel | |---|---|---| | `stInSeparator.stSenInSep` | BG mit `VERW` `IN SEP` | räumlich am Separator (Anker) | | `xOutStopper` | MB mit `VERW` `SEP` | Nummernregel ab dem BG | | `stInSenJam`, `Settings.xPluggedJam` | BG `STAU_REF-LT` | räumlich, Versatz je Symbolart; vorhanden ⇒ `xPluggedJam := TRUE` | | `xOutSwExTo3/4` | MB `AE ABZWEIG` / Weichen-MB | Nummernregel ab dem Stausensor bzw. räumlich an Weiche/Ausschleuselement | | `Settings.xPluggedPart`, `stSenPart` | BG `BT BELADEN` | räumlich; vorhanden ⇒ `TRUE` | | `xInMotorProtection`, `xOutVarioMotor` | MA im Feld + FC in `schaltschrank_elemente` | gleiche Nummer | | `xInCarouselRun` (welcher Antrieb) | FC/MA-`BEZEICHNUNG` "KREISEL-K0102", "CONVEYOR #100" | **räumlich**, nicht über Text: das CSV nennt die Kreisel `Kreisel1/2/3`, die E-Planung `K0102/K0104/K0105`. Alle Symbole, deren `BEZEICHNUNG` einen Kreisel nennt, per Mehrheit dem nächsten CSV-Kreisel zuordnen (siehe Nachprüfung) | | Steuerung, TRO-Nummernkreis, `stInOutMachineState` | `KENNZEICHNUNG` `=A1+UH01-KF107`, `mappings` | `UH01` = Steuerung, `KF107` = E/A-Station | | Plausibilisierung | `BEZEICHNUNG` "SEPARATOR STR. 14", "KR-K0102 VOR BT-BELADUNG" | Strecken-/Kreiselnummer gegen Layout prüfen | Nicht aus dieser Quelle: Scanner-Hardwarekennungen, Weichenbauart (`xNewSwitch`). Auch nicht aus den E/A-Daten, aber **je Projekt nur ein Wert**: `xInSftyOk`, `stInOutMachineState`, `xInAutomatic`, `xInErrorQuit`. Der TIA-Import enthält zwar die Not-Halt-Kanäle (`SF5000…SF6006`) und `SF0001` "ANLAGE EIN" / `SF0002` "START NACH STÖRUNG", die Referenz-SCL verdrahtet diese Parameter aber nicht mit E/A-Signalen, sondern mit dem Sicherheitsprogramm (`"DB_InterfaceSafety".stFromSafety.EStopMain….Q`) bzw. der Schrank-Struktur (`#stInOutControlUnitCabinet…`). Sie gehören als Projektkonstanten in eine Konfiguration (bei Mubea ~39 der offenen Stellen), nicht in die Brücke. ## Umsetzung (Stand 2026-10-10) 1. **`lib/e_planning.py`**: liest `*_positionsdraw.json` in `EDevice` (BMK, VERW, Bezeichnung, Kennzeichnung → Steuerung/E/A-Station, Position). 2. **Lagebezug** über `dxf_registration.derive_transform` mit den `IN SEP`-Sensoren als Rolle "Separator"; abgelegt in `cfg/dxf_registration.json` unter `|`. 3. **Regeln in `cfg/e_planning.ini`** (projektabhängig): je Rolle Layout-Art, VERW, Höchstabstand, **Sollabstand** (für die konstanten Versätze von Stausensor und Ausschleusventil — sonst gewinnt bei 0080/0084 ein näherer, fremder Stausensor des Kreisels K0102) und die Nummernregel (`MB = BG + 1`). 4. **Ausgabe** `_eplan.json` (`EplanDocument`) und Bericht `_eplan.md`. `scl_skeleton --eplan` setzt Separator-Sensor und Stopperventil ein (`SclName.todo = False`); alles andere bleibt `TODO(E-Planung)`. Ergebnis Mubea (alter Stand) mit den ausgelieferten Regeln: Separator-Sensor 21/38, Stopper 22/38, Stausensor 20/23, Ausschleusventil 20/23, Weichenventil 1/1. Den Separator-Sensor nimmt die Regel nur bis 300 mm; die Kreisel-Fälle mit 470–540 mm (z. B. BG0532 an 0044) bleiben bewusst offen. ## Nachprüfung 2026-10-15 (neuer Stand `data/Mubea/`) Lauf: `e_planning --file mubea.csv --eplan \data\Mubea\Mubea_positionsdraw.json`, dann `tro_flow --json` und `scl_skeleton --eplan --templates`. | | alter Stand | neuer Stand | |---|---|---| | Lagebezug | dx +50613.6, dy +8555.8 | **dx −151.4, dy −696.6**, Drehung 0, 23/38 Punkte, Restfehler max 541 mm | | Separator-Sensor | 21/38 | 21/38 | | Stopper | 22/38 | 22/38 | | Stausensor | 20/23 | **21/23** | | Ausschleusventil | 20/23 | **19/23** | | Weichenventil | 1/1 | 1/1 | | Antriebe | — | 11, alle mit Motorschutz | Im erzeugten `FB_Main` (18 TROs): 43 Namen aus der E-Planung, 440 Stellen `TODO(E-Planung)`. Alle 21 Konstanten und 22 Tags im SCL stehen im TIA-Import. Befunde: - **Pfad:** `--eplan Mubea/Mubea_positionsdraw.json` (Unterordner relativ zu `%SKEL_DATA%`) wird nicht gefunden; nur ein Dateiname direkt in `%SKEL_DATA%` oder ein voller Pfad geht. - **Gespeicherter Lagebezug:** der Schlüssel `|` in `cfg/dxf_registration.json` enthält nur den Dateinamen. Ein neuer Stand mit gleichem Namen übernimmt ohne `--re-register` still den alten Bezug — beim Mubea-Wechsel wären das ~51 m Versatz gewesen. - **Kreisel-Zuordnung räumlich möglich:** die Symbole, deren `BEZEICHNUNG` einen Kreisel nennt (nach dem Lagebezug, Abstand zur Boundingbox), liegen eindeutig auf einem CSV-Kreisel — **K0102 = Kreisel3 (0010)**, **K0104 = Kreisel2 (0002)**, **K0105 = Kreisel1 (0001)**; ein Ausreißer (`BG0725` "BANDBRUCHÜBERWACHUNG KR-K0105" an Kreisel2). Damit erhält jeder Kreisel seinen Antrieb (`MA0202`/`FC0202`, `MA0205`/`FC0205`, `MA0206`/`FC0206`) und K0102 seinen Geber `GF20000`. Was sich mit TIA-Import + Positionsdatei noch schließen lässt: | Offene Stellen (Mubea) | Anzahl | Weg | |---|---|---| | `stInSenJam` | ~17 | schon zugeordnet; fehlt nur TRO-Ausgang → Ausschleuselement (siehe "Offen") | | `xInCarouselRun` | ~13 | Kreisel-Zuordnung oben + Motorpaar | | Vario-Sensoren (`stSenLastPos`, `stSenJam`, `stSenFinger`, `stSenCarrInPos`), `xOutVarioMotor`, `xInMotorProtection` | ~18 | wahrscheinlich, neue Regeln über `VERW` (`SYNC P1..4`, `ZAPPLER`, `ABFR.FINGER`, `BT BELADEN`) und die Motorpaare; zu prüfen | | `xInSftyOk`, `stInOutMachineState`, `xInAutomatic`, `xInErrorQuit` | ~39 | Projektkonstante (oben), nicht aus diesen Dateien | | `nSeparatorNo`/`nSwitchNo`, Zeiten, Staubereichs-Verdrahtung | Rest | weder TIA noch Positionsdatei | Die 17 nicht zugeordneten Separatoren an den Kreiseln sind ein Standunterschied Layout ↔ E-Zeichnung, keine fehlenden Daten. Offen: - Stausensoren und Ausschleus-/Weichenventile stehen in JSON und Bericht, kommen aber noch nicht in die SCL: die TRO-JSON sagt nicht, welches Ausschleuselement bzw. welche Weiche zu welchem TRO-Ausgang gehört. - Die Lagerlinien eines `PinStore`-TRO (`arInSep[n]`) sind zugeordnet, der Generator erzeugt die Linienparameter aber noch nicht. - Scanner (`BX`) fehlen in den Mubea-Daten; Regel und Test mit `ST-Fortna_positions_.json` stehen aus. - Ein Abgleich mit passenden Ständen von CSV und E-Zeichnung für die Kreisel. - ~~TIA-Import einlesen~~ — **erledigt** 2026-10-15: `lib/hw_import.py` (`_hw.json`); `FB_CallSensors` daraus steht noch aus. - ~~Kreisel ↔ E-Kreisel (`K01xx`) räumlich zuordnen~~ — **erledigt** in `lib/merge_hw_layout.py` (Mehrheit, nur Förderer der genannten Art); in die SCL (`xInCarouselRun`) kommt es mit der Umstellung von `scl_skeleton` auf die Anlagen-JSON. - ~~Gespeicherten Lagebezug absichern~~ — **erledigt**: SHA-256 der Positionsdatei im Eintrag von `cfg/dxf_registration.json`. - ~~Unterordner in `--eplan`~~ — **erledigt** (`material_flow.resolve_input`). ## Abgleich Layoutzeichnung ↔ CSV ↔ E-Planung (2026-10-15) Zeichnung `data/mubea_layout.dxf` (aus `mubea_layout.dwg`), gelesen über alle Blockebenen mit vollständiger Blocktransformation (die `Staustrecke…`-Blöcke der Gefällestrecken sind mit gekippter Extrusionsrichtung eingefügt; ohne OCS liegen ihre Separatoren falsch). | Vergleich | Ergebnis | |---|---| | DXF ↔ `mubea.csv` | **gleiches Koordinatensystem, kein Versatz.** 38/38 Separatoren je 60–70 mm (Einfügepunkt `Separator_SP_3D` gegen CSV-Punkt, in Blockrichtung), 8/8 Scanner je 360 mm, Aus-/Einschleuselemente 22/23 bzw. 22/23 auf 0 mm (`0061`, `0064` und die Weiche `0125` sind keine eigenen Blöcke) | | E-Planung ↔ DXF | (−211, −697) mm; Speicherlinien 20/20 auf **1 mm** | | E-Planung ↔ CSV | (−151, −697) mm; 23/38 im Toleranzband | Die 20 Separatoren der Gefällestrecken passen mit dem Versatz exakt (ohne ihn liegt jeder Sensor eine Speicherlinie daneben, 235 mm). Die 12 Separatoren an Kreiseln/Strecken und die 6 Vario-Separatoren passen in **keiner** Lage (155–3438 mm, mit und ohne Versatz). Es gibt also keine starre Transformation für die ganze Anlage: der Speicher ist in der E-Zeichnung als Ganzes verschoben, der Bereich um die Kreisel ist ein anderer Planungsstand. Folge: die Kreisel-Separatoren bleiben offen, bis E-Zeichnung und Layout zum selben Stand gehören; `merge_hw_layout` warnt deshalb (23/38 = 61 %). Nebenbefund für `tro_annotate` (Kontrollansicht): es liest nur die Modellbereichs-Blöcke (12 der 38 Separatoren, die übrigen stecken in `GF_n`/`VF_n`), und der Lagebezug übernimmt den 60-mm-Einfügeversatz als scheinbare Verschiebung (dx +59.8).