hw_import --dxf: gemeinsame Zeichnung (Layout + E-Planung) als Hardwarequelle

hw_import liest mit --dxf statt der Positionsdatei eine DXF, in der Layout
und E-Planung zusammen liegen (Dematic): jeder Block mit Attribut IO ist ein
E-Bauteil (IO/VERW/BEZEICHNUNG/KENNZEICHNUNG, Einfuegepunkt), schon in
Layout-Koordinaten (HardwareDocument.layoutCoordinates). --conveyor-from-motor
nimmt den Foerderer aus der Motornummer, wenn kein K0102/#106 dasteht
("Motor KR-MA0055" -> K0055); "ILS-VARIO" zaehlt als Strecke.

merge_hw_layout: bei layoutCoordinates kein Lagebezug (Identitaet, nichts
abgelegt); --rules findet einen blossen Namen in SKEL_CFG. Neue Regeldatei
cfg/e_planning_dematic.ini (Sensor/Stopper gleiche Nummer, Weichenventil =
Nummer des Stausensors, Abstaende an dematic_merge..dxf gemessen).

Fehler behoben: zwei Antriebs-TROs auf einem Layout-Foerderer (Dematic VF_6,
TRO04/TRO06) bekamen beide denselben Vario-Motor. Jetzt Widerspruch mit
Vorschlag; scl_context faellt dann nicht auf den Motor des Foerderers zurueck.

Dematic: 115 Namen im FB_Main (alle im TIA-Import), offene Stellen 730 -> 615.
cfg/dematic_merge_tro_ids.ini: TRO-IDs der Dematic-Anlage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 18:21:20 +02:00
parent d414bd6cf3
commit 2fbd2f119d
10 changed files with 467 additions and 38 deletions
+35 -2
View File
@@ -37,7 +37,8 @@ def _tro(tro_id, type_name, seps, hosts=()):
separators=list(seps), scanners=[], reason="Test")
def layout() -> TroDocument:
def layout(second_vario: bool = False) -> TroDocument:
"""``second_vario``: TRO06 ist ein zweiter Vario-TRO auf VF_1 (Dematic VF_6)."""
parts = [_part(i, "Separator", x, y) for i, (x, y) in SEPS.items()]
parts += [
_part("0030", "Ausschleus", 0.0, 2000.0),
@@ -52,7 +53,8 @@ def layout() -> TroDocument:
_tro("TRO03", "Vario", ["0003"], ["0020"]),
_tro("TRO04", "1Sep", ["0004"]),
_tro("TRO05", "1Sep", ["0005"]),
_tro("TRO06", "1Sep", ["0006"]),
_tro("TRO06", "Vario", ["0006"], ["0020"]) if second_vario
else _tro("TRO06", "1Sep", ["0006"]),
]
return TroDocument.from_analysis(Analysis(tros=tros), source="x.csv", parts=parts)
@@ -183,6 +185,37 @@ def test_vario_antrieb_aus_dem_foerderer():
assert anlage.binding("TRO03", "drive", "senJam").status == "offen"
def test_zwei_antriebs_tros_auf_einem_foerderer_sind_widerspruch():
"""Jeder Vario-TRO hat seinen eigenen Motor; die Mehrheit je Foerderer
kennt nur einen - nicht beiden denselben Motor geben."""
anlage = run(doc=layout(second_vario=True))
for tro in ("TRO03", "TRO06"):
motor = anlage.binding(tro, "drive", "motor")
assert (motor.bmk, motor.status) == ("MA0210", "widerspruch")
assert "TRO03, TRO06" in motor.note and "von Hand" in motor.note
assert anlage.binding(tro, "drive", "motorProtection").status == "widerspruch"
def test_gemeinsame_zeichnung_ohne_lagebezug(tmp_path):
"""hw_import --dxf: E-Symbole stehen schon in Layout-Koordinaten - kein
Lagebezug wird ermittelt oder abgelegt."""
hw = hardware()
hw.layout_coordinates = True
anlage = run(hw=hw, transform=None, tmp_path=tmp_path)
reg = anlage.registration
assert (reg.dx, reg.dy, reg.rotation, reg.source) == (0.0, 0.0, 0.0, "zeichnung")
assert not list(tmp_path.iterdir())
assert anlage.binding("TRO01", "separator1", "sensor").bmk == "BG0101"
def test_dematic_regeln_gleiche_nummer():
rules, _ = load_rules(RULES.parent / "e_planning_dematic.ini")
by_role = {r.role: r for r in rules}
assert by_role["Separator.stopper"].number_from == "Separator.sensor"
assert by_role["Separator.stopper"].number_offset == 0
assert by_role["Ausschleus.valve"].number_offset == 0
def test_foerderer_mit_zu_wenig_stimmen_bleibt_offen():
hw = hardware()
hw.devices = [d for d in hw.devices if d.bmk != "BG0802"]