Fehlerhandling in eigene Klasse ausgelagert

This commit is contained in:
2025-12-16 16:27:23 +01:00
parent 45a56287b8
commit b89525556b
14 changed files with 905 additions and 135 deletions
+354 -4
View File
@@ -183,18 +183,41 @@ Hinweis: Diese Ansicht ist besonders nützlich zur **vorbereitenden Bestellplanu
## Übersicht ## Übersicht
Das Programm führt während der Verarbeitung umfassende Validierungen durch und erkennt verschiedene Arten von Fehlern im Layout. Falls Fehler auftreten, schreibt `getpositions` **automatisch** eine JSON-Datei mit allen erkannten Fehlern und Warnungen in den `work`-Ordner. Diese Datei hat den Namen `*_errors.json` (wobei `*` der Name der verarbeiteten DXF-Datei ist). Das Programm führt während der Verarbeitung umfassende Validierungen durch und erkennt verschiedene Arten von Fehlern im Layout. Die Fehlerbehandlung unterscheidet sich je nach Anwendungsfall:
### Zwei Haupt-Workflows
Das Kabeltool unterstützt zwei verschiedene Workflows:
1. **Cable Routing Workflow** (`getexdraw.bat`):
- Schritt 1: `getpositions.py` - Extrahiert Positionen und validiert Layout
- Schritt 2: `routing.py` - Berechnet Kabelwege über Graph-Algorithmen
- Schritt 3: `drawdxf.py` - Erzeugt DXF mit Kabelwegen und Excel-Listen
- **Ausgabe**: `*_cables.dxf`, `*_cables.xlsx`, `*_BOM.xlsx`
2. **I/O Conversion Workflow** (`ioconverter.bat`):
- Schritt 1: `getpositions.py` - Extrahiert Positionen und validiert Layout
- Schritt 2: `portalexport.py` - Konvertiert zu Excel-Formaten (TIA, WSCAD, EA)
- **Ausgabe**: `*_TIA.xlsx`, `*_WSCAD.xlsx`, `*_EA.xlsx`
### Fehler- und Warnungskategorien
Die Fehlerbehandlung unterscheidet zwischen zwei Kategorien: Die Fehlerbehandlung unterscheidet zwischen zwei Kategorien:
- **Fehler (errors)**: Schwerwiegende Probleme, die die Korrektheit der Ausgabe beeinträchtigen oder zum Abbruch führen - **Fehler (errors)**: Schwerwiegende Probleme, die die Korrektheit der Ausgabe beeinträchtigen oder zum Abbruch führen
- **Warnungen (warnings)**: Hinweise auf potenzielle Probleme, die Programm kann aber fortfahren - **Warnungen (warnings)**: Hinweise auf potenzielle Probleme, das Programm kann aber fortfahren
### Fehlerausgabe
**Für beide Workflows gilt:**
- Falls Fehler oder Warnungen auftreten, schreibt `getpositions.py` **automatisch** eine JSON-Datei `*_errors.json` in den `work`-Ordner
- Im **Cable Routing Workflow** werden zusätzliche Fehler in der Excel-Datei `*_cables.xlsx` als separate Worksheets ausgegeben (siehe [ERR-Worksheets](#erweiterte-ausgabe-im-fehlerfall))
Im Ordner [testdata/](testdata/) finden sich Beispiel-DXF-Dateien, die gezielt bestimmte Fehlerfälle demonstrieren (z.B. [easy_3tunnels_errors.json](testdata/easy_3tunnels_errors.json), [easy_tunnelerror1.json](testdata/easy_tunnelerror1.json)). Im Ordner [testdata/](testdata/) finden sich Beispiel-DXF-Dateien, die gezielt bestimmte Fehlerfälle demonstrieren (z.B. [easy_3tunnels_errors.json](testdata/easy_3tunnels_errors.json), [easy_tunnelerror1.json](testdata/easy_tunnelerror1.json)).
## Fehlertypen und ihre Bedeutung ## Allgemeine Fehler und Warnungen (beide Workflows)
Die folgende Tabelle zeigt alle möglichen Fehler- und Warnungstypen, die von `getpositions.py` erkannt werden: Die folgende Tabelle zeigt alle möglichen Fehler- und Warnungstypen, die von `getpositions.py` erkannt werden. Diese gelten **für beide Workflows** (Cable Routing und I/O Conversion):
| Fehlertyp | Kategorie | Beschreibung | Ursache | Behebung | | Fehlertyp | Kategorie | Beschreibung | Ursache | Behebung |
|-----------|-----------|--------------|---------|----------| |-----------|-----------|--------------|---------|----------|
@@ -209,6 +232,333 @@ Die folgende Tabelle zeigt alle möglichen Fehler- und Warnungstypen, die von `g
| `mapping_warnings` → `Ungültiger Pfad in Kennzeichnung` | Warnung | KENNZEICHNUNG hat falsches Format | Trennzeichen `+`, `-` oder `=` fehlen oder falsch positioniert | KENNZEICHNUNG-Format korrigieren (z.B. `=A01+UH01-KF1DQ04`) | | `mapping_warnings` → `Ungültiger Pfad in Kennzeichnung` | Warnung | KENNZEICHNUNG hat falsches Format | Trennzeichen `+`, `-` oder `=` fehlen oder falsch positioniert | KENNZEICHNUNG-Format korrigieren (z.B. `=A01+UH01-KF1DQ04`) |
| `missing_sps_prefix` | Fehler | SPS-Präfix fehlt für Block-ID | Beim Zusammenführen von Blöcken fehlt der SPS-Präfix | SPS-Attribut in Block ergänzen | | `missing_sps_prefix` | Fehler | SPS-Präfix fehlt für Block-ID | Beim Zusammenführen von Blöcken fehlt der SPS-Präfix | SPS-Attribut in Block ergänzen |
## Detaillierte Beschreibung der Warnungen (Warnings)
Warnungen (Warnings) sind **nicht-kritische Probleme**, bei denen das Programm zwar fortfahren kann, aber das Ergebnis möglicherweise unvollständig oder fehlerhaft ist. Im Gegensatz zu Fehlern führen Warnungen nicht zum Abbruch, sollten aber trotzdem behoben werden, um die Qualität der Ausgabe zu gewährleisten.
### 1. `missing_attributes` (Fehlende oder unvollständige Block-Attribute)
**Was wird geprüft:**
- Jeder Block im Layout sollte mindestens zwei zusammengehörige Blöcke haben (z.B. einen für das Bauteil und einen für das Kabel)
- Blöcke müssen bestimmte Pflichtattribute enthalten (z.B. SPS, KENNZEICHNUNG, ARTINR)
**Wann tritt die Warnung auf:**
- Nur ein einzelner Block mit einer bestimmten ID gefunden wird
- Der Block hat fehlende Attribute (z.B. kein SPS-Präfix, keine KENNZEICHNUNG)
- Die Block-Zuordnung ist unvollständig
**Beispiel-Warnung:**
```json
"missing_attributes": {
"BX0101": "Nur ein Block und/oder fehlende Attribute: dict_keys(['A', 'B', 'C', 'ARTINR'])"
}
```
**Mögliche Ursachen:**
- Block wurde nur einmal statt zweimal gezeichnet (Rahmen innen/außen fehlt)
- Attribute wie `SPS`, `KENNZEICHNUNG` oder `IO` wurden nicht ausgefüllt
- Block-Kopie beim Zeichnen vergessen
**Behebung:**
- Überprüfen Sie den betroffenen Block im DXF-Layout
- Ergänzen Sie fehlende Attribute (besonders SPS, KENNZEICHNUNG)
- Falls nötig, korrigieren Sie die Block-Struktur gemäß den Layoutrichtlinien
**Auswirkung:**
- Der betroffene Block wird **nicht verkabelt** und **nicht in die Ausgabe** übernommen
- Keine Kabellängenberechnung für dieses Bauteil
- Block erscheint nicht in der Stückliste
---
### 2. `tunnel_missing_length` (Fehlende Längenangabe bei Tunnel)
**Was wird geprüft:**
- Jeder Tunnel-Block sollte ein Attribut `LAENGE` haben, das die physische Länge des Tunnels angibt
- Alternativ kann die Länge über MTEXT-Eintrag (`TUNNEL<nr>-<länge>`) definiert werden
**Wann tritt die Warnung auf:**
- Ein Tunnel wurde gefunden, aber das `LAENGE`-Attribut fehlt oder ist leer
- Keine Längenangabe in der MTEXT-Beschriftung vorhanden
**Beispiel-Warnung:**
```json
"tunnel_missing_length": {
"TUNNEL1": "Tunnel 'TUNNEL1' hat keine LAENGE-Angabe. Verwende Default-Länge: 5m"
}
```
**Mögliche Ursachen:**
- Das `LAENGE`-Attribut wurde beim Zeichnen des Tunnel-Blocks vergessen
- MTEXT-Beschriftung folgt nicht dem erwarteten Muster (`TUNNEL<nr>-<länge>`)
- Tunnel wurde aus älterer Layoutversion übernommen, wo Längenangaben noch nicht Pflicht waren
**Behebung:**
- Öffnen Sie den Tunnel-Block im DXF-Layout
- Fügen Sie das Attribut `LAENGE` hinzu und tragen Sie die tatsächliche Tunnel-Länge in Metern ein
- Alternativ: Verwenden Sie MTEXT im Format `TUNNEL1-12.5` (für 12,5 Meter)
**Auswirkung:**
- Es wird eine **Default-Länge von 5 Metern** verwendet
- Die Kabellängenberechnung kann dadurch **ungenau** sein
- In der Routing-Berechnung wird mit dem Default-Wert gearbeitet, was zu falschen Kabellängen führen kann
---
### 3. `mapping_warnings` (Probleme bei KENNZEICHNUNG-Zuordnung)
**Was wird geprüft:**
- Jeder Sensor/Aktor sollte ein Attribut `KENNZEICHNUNG` haben
- Die KENNZEICHNUNG muss dem Format `=<Anlage>+<UV>-<Karte>` entsprechen (z.B. `=AH01+UH02-KF1FDI7`)
- Die Zuordnung zu einem Unterverteiler muss eindeutig möglich sein
**Wann tritt die Warnung auf:**
#### 3a. "keine KENNZEICHNUNG vorhanden"
- Das Attribut `KENNZEICHNUNG` fehlt komplett im Block
**Beispiel-Warnung:**
```json
"mapping_warnings": {
"MA0099": "keine KENNZEICHNUNG vorhanden"
}
```
**Ursachen:**
- Attribut wurde beim Erstellen des Blocks vergessen
- Block-Template war unvollständig
- Manuelle Bearbeitung hat das Attribut gelöscht
**Behebung:**
- Fügen Sie das Attribut `KENNZEICHNUNG` im Block hinzu
- Tragen Sie den korrekten Wert ein (z.B. `=A01+UH01-KF1DQ04`)
**Auswirkung:**
- Sensor/Aktor wird **nicht verkabelt**
- Keine Zuordnung zu einem Unterverteiler möglich
- Element erscheint nicht in der Kabelberechnung
---
#### 3b. "Ungültiger Pfad in Kennzeichnung"
- KENNZEICHNUNG ist vorhanden, aber das Format stimmt nicht
- Trennzeichen (`=`, `+`, `-`) fehlen oder sind falsch positioniert
- Es werden nicht genau drei Teile (Anlage, UV, Karte) erkannt
**Beispiel-Warnungen:**
```json
"mapping_warnings": {
"BG3240": "Ungültiger Pfad in Kennzeichnung: UH01-KF1DQ04: +, - oder = fehlen an entsprechender Stelle, keine drei Teile sichtbar",
"MA0062": "Ungültiger Pfad in Kennzeichnung: AH01+UH02"
}
```
**Mögliche Ursachen:**
- Falsches Format verwendet (z.B. `UH01-KF1DQ04` statt `=A01+UH01-KF1DQ04`)
- Trennzeichen fehlen (z.B. `AH01UH02KF1DQ04`)
- Nur Teile der Kennzeichnung eingetragen (z.B. nur `AH01+UH02` ohne Kartenangabe)
- Sonderzeichen oder Leerzeichen in der Kennzeichnung
**Behebung:**
- Korrigieren Sie die KENNZEICHNUNG im Block
- Verwenden Sie das korrekte Format: `=<Anlage>+<UV>-<Karte>`
- Beispiel: `=AH01+UH02-KF1FDI7`
- Achten Sie auf die **exakte Position** von `=`, `+` und `-`
**Auswirkung:**
- Sensor/Aktor wird **nicht verkabelt**
- Keine Zuordnung zu einem Unterverteiler möglich
- Element erscheint nicht in der Kabelberechnung
---
### Zusammenfassung: Umgang mit Warnungen
**Wichtig:** Auch wenn das Programm bei Warnungen fortfährt, sollten diese **nicht ignoriert** werden. Warnungen führen oft dazu, dass:
- Bauteile nicht verkabelt werden
- Kabellängen falsch berechnet werden
- Stücklisten unvollständig sind
**Empfohlene Vorgehensweise:**
1. Prüfen Sie nach jedem Programmlauf, ob eine `*_errors.json`-Datei erstellt wurde
2. Arbeiten Sie alle Warnungen systematisch ab
3. Führen Sie das Programm erneut aus, bis keine Warnungen mehr auftreten
4. Dokumentieren Sie wiederkehrende Probleme und passen Sie ggf. die Block-Templates an
---
## Cable Routing spezifische Fehler
Die folgenden Fehler treten **nur im Cable Routing Workflow** (`getexdraw.bat`) auf. Sie werden während der Routing- und Zeichnungsphase erkannt und in der Excel-Datei `*_cables.xlsx` als separate Worksheets ausgegeben.
### Fehlertypen im Routing-Prozess
| Fehlertyp | Ausgabe in Excel | Beschreibung | Ursache | Behebung |
|-----------|------------------|--------------|---------|----------|
| **Equipment Connection Errors** | `ERR-Equipment-Connection` | Sensoren, Aktoren oder Unterverteiler können nicht mit Kabeltrassen verbunden werden | Abstand zur nächsten Kabeltrasse überschreitet die konfigurierte Toleranz (Standard: 5000 mm) | Position des Elements anpassen oder Kabeltrasse näher zum Element verlegen; Toleranz in `allgemein.cfg` unter `[Sensoren]` → `ConnectionTolerances` erhöhen |
| **Routing Errors** | `ERR-Routing` | Kabelweg zwischen Unterverteiler und Sensor/Aktor kann nicht berechnet werden | Keine Verbindung im Graph zwischen Start- und Zielpunkt; UV oder Sensor nicht angebunden; fehlende Kabeltrasse | Kabeltrassen-Geometrie prüfen und Lücken schließen; fehlende Unterverteiler ergänzen; Equipment-Connection-Fehler beheben |
| **Tunnel Connection Errors** | `ERR-Equipment-Connection` | Tunnel-Eingang oder -Ausgang kann nicht mit Kabeltrassen verbunden werden | Tunnel-Position liegt zu weit von nächster Kabeltrasse entfernt | Tunnel-Position anpassen oder Kabeltrasse zum Tunnel verlegen |
### Detail-Beschreibungen der Routing-Fehler
#### Equipment Connection Errors (ERR-Equipment-Connection)
**Was wird geprüft:**
- Jedes Equipment-Element (Sensor, Aktor, Unterverteiler, Tunnel) muss innerhalb der konfigurierten Toleranz zu einer Kabeltrasse liegen
- Die Toleranz ist in `allgemein.cfg` unter `[Sensoren]` → `ConnectionTolerances` definiert (Standard: 3000 mm)
**Ausgabe in Excel:**
Das Worksheet `ERR-Equipment-Connection` enthält folgende Spalten:
- **Type**: Art des Elements (Sensor / Actuator, Subdistributor, Tunnel)
- **ID**: Bezeichner des Elements (z.B. MA0062, UH01)
- **x, y**: Koordinaten der Position im Layout
**Beispiel:**
| Type | ID | x | y |
|------|-----|------|------|
| Sensor / Actuator | MA0062 | 15000 | 8000 |
| Subdistributor | UC0105 | 2000 | 12000 |
**Mögliche Ursachen:**
- Element wurde zu weit entfernt von Kabeltrassen platziert
- Kabeltrasse endet vor dem Equipment
- Falscher Layer für Kabeltrassen verwendet (nicht in `allgemein.cfg` konfiguriert)
- `REALE_POSITION`-Attribut zeigt auf falsche Position
**Behebung:**
1. Öffnen Sie das Layout und navigieren Sie zu den angegebenen Koordinaten
2. Prüfen Sie den Abstand zur nächsten Kabeltrasse
3. Verschieben Sie entweder das Element näher zur Trasse oder verlängern Sie die Trasse
4. Alternativ: Erhöhen Sie die `ConnectionTolerances` in `allgemein.cfg` (nicht empfohlen für Produktivbetrieb)
**Auswirkung:**
- Element wird **nicht verkabelt**
- Keine Kabellängenberechnung für dieses Element
- Element erscheint nicht in der Kabelübersicht
- Folge-Fehler in `ERR-Routing` möglich
---
#### Routing Errors (ERR-Routing)
**Was wird geprüft:**
- Für jede Sensor-Unterverteiler-Verbindung muss ein Pfad im Kabeltrassen-Graph existieren
- Der Graph basiert auf den Kabeltrassen-Geometrien und den Equipment-Verbindungen
**Ausgabe in Excel:**
Das Worksheet `ERR-Routing` enthält folgende Spalten:
- **Subdistributor**: Unterverteiler-ID (z.B. UH01)
- **Sensor / Actuator**: Element-ID (z.B. MA0062)
- **Details**: Detaillierte Fehlerbeschreibung
**Mögliche Fehlermeldungen:**
- `"Distributor not found in given layout"` - UV in KENNZEICHNUNG erwähnt, aber nicht im Layout vorhanden
- `"Subdistributor and sensor / actuator not connected to racks"` - Beide Endpunkte nicht angebunden
- `"Sensor / actuator not connected to racks"` - Nur Sensor nicht angebunden (siehe ERR-Equipment-Connection)
- `"Subdistributor not connected to racks"` - Nur UV nicht angebunden (siehe ERR-Equipment-Connection)
- `"Failed routing (not caused by missing connection)"` - Andere Routing-Probleme (z.B. Lücke im Kabeltrassen-Netz)
**Beispiel:**
| Subdistributor | Sensor / Actuator | Details |
|----------------|-------------------|---------|
| UH01 | MA0062 | Sensor / actuator not connected to racks |
| UC0105 | - | Distributor not found in given layout |
| UH02 | BG3240 | Failed routing (not caused by missing connection) |
**Mögliche Ursachen:**
- Equipment-Connection-Fehler (siehe oben)
- Fehlende oder fehlerhafte KENNZEICHNUNG (Verweis auf nicht existierenden UV)
- Lücke im Kabeltrassen-Netz (zwei nicht verbundene Trassen-Abschnitte)
- Fehlende Kabeltrassen-Verbindung zwischen zwei Ebenen
- Tunnel nicht korrekt definiert
**Behebung:**
1. **Bei "Distributor not found in given layout":**
- Prüfen Sie, ob der UV-Block im Layout vorhanden ist
- Prüfen Sie die KENNZEICHNUNG der betroffenen Sensoren
- Fügen Sie fehlenden UV hinzu oder korrigieren Sie die KENNZEICHNUNG
2. **Bei Connection-Fehlern:**
- Beheben Sie zuerst die Equipment-Connection-Fehler aus `ERR-Equipment-Connection`
- Führen Sie das Programm erneut aus
3. **Bei "Failed routing":**
- Prüfen Sie visuell die Kabeltrassen zwischen UV und Sensor
- Suchen Sie nach Lücken oder fehlenden Verbindungen
- Prüfen Sie, ob alle Kabeltrassen auf den konfigurierten Layern liegen
- Verwenden Sie die `--graph` Option von `routing.py` zur Visualisierung des Graphen
**Auswirkung:**
- Betroffene Kabelverbindung wird **nicht berechnet**
- Keine Kabellänge in der Ausgabe
- Kabel fehlt in Stückliste
- Kabel wird nicht in DXF gezeichnet
---
#### Tunnel Connection Errors
**Was wird geprüft:**
- Tunnel-Eingänge und -Ausgänge müssen wie normale Equipment-Elemente mit Kabeltrassen verbindbar sein
- Beide Tunnel-Positionen müssen innerhalb der ConnectionTolerances liegen
**Ausgabe in Excel:**
Tunnel-Connection-Fehler erscheinen im Worksheet `ERR-Equipment-Connection` mit Type = "Tunnel"
**Mögliche Ursachen:**
- Tunnel-Block wurde zu weit von Kabeltrasse positioniert
- Tunnel-Position falsch eingetragen (MTEXT oder Block-Attribut)
- Kabeltrasse endet vor Tunnel-Ein-/Ausgang
**Behebung:**
1. Prüfen Sie die Tunnel-Positionen im Layout
2. Verlängern Sie Kabeltrassen bis zu den Tunnel-Positionen
3. Korrigieren Sie ggf. die Tunnel-Positionen
4. Prüfen Sie, ob beide Tunnel-Enden (Ein- und Ausgang) definiert sind
**Auswirkung:**
- Tunnel kann nicht für Routing verwendet werden
- Kabelwege, die durch den Tunnel führen sollten, schlagen fehl
- Längere Kabelwege über alternative Routen (falls vorhanden)
---
### Hinweise zur Excel-Fehlerausgabe (Cable Routing)
Die Fehler-Worksheets in `*_cables.xlsx` erscheinen **nur**, wenn tatsächlich Fehler aufgetreten sind:
- **ERR-Equipment-Connection** - nur bei Connection-Fehlern
- **ERR-Routing** - nur bei Routing-Fehlern
- **ERR-Attributes** - nur bei Attribut-Fehlern (aus getpositions)
**Workflow zur Fehlerbehebung:**
1. Öffnen Sie `*_cables.xlsx` und prüfen Sie, welche ERR-Worksheets vorhanden sind
2. Beheben Sie **zuerst** die Equipment-Connection-Fehler
3. Führen Sie das Programm erneut aus
4. Beheben Sie verbleibende Routing-Fehler
5. Wiederholen Sie, bis keine ERR-Worksheets mehr erstellt werden
---
## I/O Conversion Workflow - Hinweise
Der **I/O Conversion Workflow** (`ioconverter.bat`) führt **keine Routing-Berechnungen** durch und erzeugt daher auch keine Routing-spezifischen Fehler. Es werden ausschließlich die **allgemeinen Fehler und Warnungen** aus `getpositions.py` gemeldet (siehe [Allgemeine Fehler und Warnungen](#allgemeine-fehler-und-warnungen-beide-workflows)).
### Ausgabedateien bei Fehlern
- `*_errors.json` - enthält alle Fehler und Warnungen aus getpositions
- `*_positionsconv.json` - Zwischenergebnis mit extrahierten Positionen
- `*_TIA.xlsx`, `*_WSCAD.xlsx`, etc. - werden auch bei Warnungen erzeugt, können aber unvollständig sein
### Wichtige Hinweise
- **Fehlende Attribute** führen dazu, dass Elemente in den Export-Dateien fehlen
- **Fehlende KENNZEICHNUNG** verhindert die korrekte Zuordnung zu Unterverteilern
- **Doppelte IDs** können zu falschen Einträgen in den Excel-Listen führen
**Empfehlung:** Beheben Sie alle Warnungen aus `*_errors.json`, bevor Sie die Export-Dateien an nachgelagerte Systeme (TIA Portal, WSCAD) übergeben.
---
## Struktur der Error-JSON-Datei ## Struktur der Error-JSON-Datei
Die `*_errors.json`-Datei ist wie folgt strukturiert: Die `*_errors.json`-Datei ist wie folgt strukturiert:
+113 -39
View File
@@ -11,8 +11,9 @@ import math
from collections import defaultdict from collections import defaultdict
import configparser import configparser
import updateconfignames as uc import updateconfignames as uc
from pathlib import Path
from error_collector import ErrorCollector, write_json_file
@dataclass @dataclass
@@ -20,6 +21,7 @@ class Point:
x: float x: float
y: float y: float
@dataclass @dataclass
class Polyline: class Polyline:
id: str id: str
@@ -34,12 +36,12 @@ class Polyline:
return ret return ret
@dataclass @dataclass
# Fehlgeschlagene Anbindung von einem Sensor / Dist zu einem Rack # Fehlgeschlagene Anbindung von einem Sensor / Dist zu einem Rack
class Error_Connection: class Error_Connection:
name: str name: str
coords: Point coords: Point
@dataclass @dataclass
# Felgeschlagene Verbindung von einem Dist zu Sensor(en) aus beliebigem Grund # Felgeschlagene Verbindung von einem Dist zu Sensor(en) aus beliebigem Grund
class Error_Routing: class Error_Routing:
unterverteiler: str unterverteiler: str
@@ -59,13 +61,8 @@ class RackGeometry:
@dataclass @dataclass
class Polylines: class Polylines:
"""Enthält alle Kabel-Polylinien und Rack-Geometrien (ohne Fehlerbehandlung)."""
kabel: List[Polyline] kabel: List[Polyline]
errors_routing: List[Error_Routing]
errors_sensors: List[Error_Connection]
errors_dists: List[Error_Connection]
errors_dists_not_in_layout: List[str]
errors_sensors_not_in_layout: List[str]
errors_missing_attributes: Dict[str, str]
rack_geometry: Dict[str, RackGeometry] = field(default_factory=dict) rack_geometry: Dict[str, RackGeometry] = field(default_factory=dict)
@@ -336,22 +333,69 @@ def _calculate_text_placement(pt1, pt2, text_type='sensor', item_index=0, total_
def model_from_json(json_file): def model_from_json(json_file):
""" """
Lädt die Polylinien- und Geometriedaten aus einer JSON-Datei und gibt ein Polylines-Objekt zurück. Lädt die Polylinien- und Geometriedaten aus einer JSON-Datei und gibt Polylines-Objekt und ErrorCollector zurück.
Args: Args:
json_file (str): Pfad zur JSON-Datei. json_file (str): Pfad zur JSON-Datei.
Returns: Returns:
Polylines: Das geladene Polylinien-Objekt. tuple: (Polylines-Objekt, ErrorCollector-Objekt)
""" """
with open(json_file, encoding='utf-8') as fh: with open(json_file, encoding='utf-8') as fh:
data = json.load(fh) data = json.load(fh)
# ErrorCollector für Fehler und Warnungen initialisieren
error_collector = ErrorCollector()
# Fehler-Daten aus JSON extrahieren und in ErrorCollector speichern
error_fields = {
'errors_routing': [],
'errors_sensors': [],
'errors_dists': [],
'errors_dists_not_in_layout': [],
'errors_sensors_not_in_layout': [],
'errors_missing_attributes': {},
'errors_tunnels': []
}
# Fehler aus data extrahieren
for field in error_fields.keys():
if field in data:
error_fields[field] = data.pop(field)
# Fehler zum ErrorCollector hinzufügen
errors_dict = {}
warnings_dict = {}
# Kritische Fehler
if error_fields['errors_routing']:
errors_dict['routing'] = error_fields['errors_routing']
if error_fields['errors_sensors']:
errors_dict['sensors_connection'] = error_fields['errors_sensors']
if error_fields['errors_dists']:
errors_dict['dists_connection'] = error_fields['errors_dists']
if error_fields['errors_dists_not_in_layout']:
errors_dict['dists_not_in_layout'] = error_fields['errors_dists_not_in_layout']
if error_fields['errors_sensors_not_in_layout']:
errors_dict['sensors_not_in_layout'] = error_fields['errors_sensors_not_in_layout']
if error_fields['errors_tunnels']:
errors_dict['tunnels'] = error_fields['errors_tunnels']
# Warnungen
if error_fields['errors_missing_attributes']:
warnings_dict['missing_attributes'] = error_fields['errors_missing_attributes']
if errors_dict:
error_collector.add_errors(errors_dict)
if warnings_dict:
error_collector.add_warnings(warnings_dict)
# Polylines-Objekt aus den verbleibenden Daten erstellen
plines = from_dict( plines = from_dict(
data_class=Polylines, data_class=Polylines,
data=data data=data
) )
return plines return plines, error_collector
def parse_sensors_from_json(positions_json): def parse_sensors_from_json(positions_json):
""" """
@@ -414,7 +458,7 @@ def mark_missings(all_artnrs):
if artnr not in bezeichner_cfg["Sivasnummern"]: if artnr not in bezeichner_cfg["Sivasnummern"]:
bezeichner_cfg["Missing"][artnr] = "" bezeichner_cfg["Missing"][artnr] = ""
def write_excel_from_json(plines: Polylines, sens2cable: dict, outpath: str, with_bom=True): def write_excel_from_json(plines: Polylines, sens2cable: dict, outpath: str, error_collector: ErrorCollector = None, with_bom=True):
""" """
Erstellt Excel-Reports (Kabelübersicht, Fehlerlisten, Stückliste) aus den Polylinien- und Zuordnungsdaten. Erstellt Excel-Reports (Kabelübersicht, Fehlerlisten, Stückliste) aus den Polylinien- und Zuordnungsdaten.
@@ -422,6 +466,7 @@ def write_excel_from_json(plines: Polylines, sens2cable: dict, outpath: str, wit
plines (Polylines): Die Polylinien- und Geometriedaten. plines (Polylines): Die Polylinien- und Geometriedaten.
sens2cable (dict): Mapping von Sensor-IDs zu Kabel-Artikelnummern. sens2cable (dict): Mapping von Sensor-IDs zu Kabel-Artikelnummern.
outpath (str): Pfad zur Ausgabedatei. outpath (str): Pfad zur Ausgabedatei.
error_collector (ErrorCollector, optional): ErrorCollector mit Fehlern und Warnungen.
with_bom (bool, optional): Ob zusätzlich eine Stückliste (BOM) erzeugt werden soll. Default: True. with_bom (bool, optional): Ob zusätzlich eine Stückliste (BOM) erzeugt werden soll. Default: True.
""" """
# 1. Daten aggregieren und für die Reports vorbereiten # 1. Daten aggregieren und für die Reports vorbereiten
@@ -429,11 +474,11 @@ def write_excel_from_json(plines: Polylines, sens2cable: dict, outpath: str, wit
# 2. Haupt-Excel-Datei (Kabellängen und Fehler) erstellen # 2. Haupt-Excel-Datei (Kabellängen und Fehler) erstellen
wb_main = Workbook() wb_main = Workbook()
_create_cable_list_sheet(wb_main.active, plines, sens2cable, bezeichner_cfg) _create_cable_list_sheet(wb_main.active, plines, sens2cable, bezeichner_cfg)
_create_cable_summary_sheet(wb_main.create_sheet(), processed_data) _create_cable_summary_sheet(wb_main.create_sheet(), processed_data)
_create_rack_lengths_sheet(wb_main.create_sheet(), plines) _create_rack_lengths_sheet(wb_main.create_sheet(), plines)
_create_error_sheets(wb_main, plines) _create_error_sheets(wb_main, error_collector)
wb_main.save(outpath) wb_main.save(outpath)
print("Cable-Summary exported to Excel-file") print("Cable-Summary exported to Excel-file")
@@ -582,51 +627,74 @@ def _create_rack_lengths_sheet(ws, plines):
else: else:
ws.append([rackname, rack_geom.length]) ws.append([rackname, rack_geom.length])
def _create_error_sheets(wb, plines): def _create_error_sheets(wb, error_collector: ErrorCollector = None):
""" """
Erstellt die Arbeitsblätter für alle aufgetretenen Fehler (Equipment-Connection, Routing, Attribute). Erstellt die Arbeitsblätter für alle aufgetretenen Fehler (Equipment-Connection, Routing, Attribute).
Args: Args:
wb (Workbook): Das Excel-Workbook. wb (Workbook): Das Excel-Workbook.
plines (Polylines): Die Polylinien- und Geometriedaten. error_collector (ErrorCollector, optional): ErrorCollector mit Fehlern und Warnungen.
""" """
if not error_collector:
return
errors = error_collector.errors
warnings = error_collector.warnings
# Sheet: ERR-Equipment-Connection # Sheet: ERR-Equipment-Connection
if plines.errors_sensors or plines.errors_dists: errors_sensors = errors.get('sensors_connection', [])
errors_dists = errors.get('dists_connection', [])
if errors_sensors or errors_dists:
ws = wb.create_sheet("ERR-Equipment-Connection") ws = wb.create_sheet("ERR-Equipment-Connection")
ws.append(["Type", "ID", "x", "y"]) ws.append(["Type", "ID", "x", "y"])
ws.column_dimensions['A'].width = 20 ws.column_dimensions['A'].width = 20
for error in plines.errors_sensors: for error in errors_sensors:
ws.append(["Sensor / Actuator", error.name, int(error.coords.x), int(error.coords.y)]) ws.append(["Sensor / Actuator", error['name'], int(error['coords']['x']), int(error['coords']['y'])])
for error in plines.errors_dists: for error in errors_dists:
ws.append(["Subistributor", error.name, int(error.coords.x), int(error.coords.y)]) ws.append(["Subdistributor", error['name'], int(error['coords']['x']), int(error['coords']['y'])])
# Sheet: ERR-Routing # Sheet: ERR-Routing
if plines.errors_routing: errors_routing = errors.get('routing', [])
errors_dists_not_in_layout = errors.get('dists_not_in_layout', [])
if errors_routing:
ws = wb.create_sheet("ERR-Routing") ws = wb.create_sheet("ERR-Routing")
ws.append(["Subdistributor", "Sensor / Actuator", "Details"]) ws.append(["Subdistributor", "Sensor / Actuator", "Details"])
ws.column_dimensions['A'].width = 20 ws.column_dimensions['A'].width = 20
ws.column_dimensions['B'].width = 20 ws.column_dimensions['B'].width = 20
ws.column_dimensions['C'].width = 50 ws.column_dimensions['C'].width = 50
nicht_angebunden = {e.name for e in plines.errors_sensors + plines.errors_dists}
for error in plines.errors_routing: nicht_angebunden = {e['name'] for e in errors_sensors + errors_dists}
uv, uv_nicht_angebunden = error.unterverteiler, error.unterverteiler in nicht_angebunden
if uv in plines.errors_dists_not_in_layout: for error in errors_routing:
uv = error['unterverteiler']
uv_nicht_angebunden = uv in nicht_angebunden
if uv in errors_dists_not_in_layout:
ws.append([uv, "-", "Distributor not found in given layout."]) ws.append([uv, "-", "Distributor not found in given layout."])
continue continue
for sensor in error.sensoren:
for sensor in error['sensoren']:
sensor_nicht_angebunden = sensor in nicht_angebunden sensor_nicht_angebunden = sensor in nicht_angebunden
if sensor_nicht_angebunden and uv_nicht_angebunden: grund = "Subdistributor and sensor / actuator not connected to racks" if sensor_nicht_angebunden and uv_nicht_angebunden:
elif sensor_nicht_angebunden: grund = "Sensor / actuator not connected to racks" grund = "Subdistributor and sensor / actuator not connected to racks"
elif uv_nicht_angebunden: grund = "Subdistributor not connected to racks" elif sensor_nicht_angebunden:
else: grund = "Failed routing (not caused by missing connection)" grund = "Sensor / actuator not connected to racks"
elif uv_nicht_angebunden:
grund = "Subdistributor not connected to racks"
else:
grund = "Failed routing (not caused by missing connection)"
ws.append([uv, sensor, grund]) ws.append([uv, sensor, grund])
# Sheet: ERR-Attributes # Sheet: ERR-Attributes
if plines.errors_missing_attributes: missing_attributes = warnings.get('missing_attributes', {})
if missing_attributes:
ws = wb.create_sheet("ERR-Attributes") ws = wb.create_sheet("ERR-Attributes")
ws.append(["ID", "Error Detail"]) ws.append(["ID", "Error Detail"])
ws.column_dimensions['B'].width = 35 ws.column_dimensions['B'].width = 35
for sname, err_msg in plines.errors_missing_attributes.items(): for sname, err_msg in missing_attributes.items():
ws.append([sname, err_msg]) ws.append([sname, err_msg])
def _create_bom_workbook(outpath, processed_data, bezeichner_cfg): def _create_bom_workbook(outpath, processed_data, bezeichner_cfg):
@@ -873,8 +941,8 @@ if __name__ == '__main__':
print(f"file {json_file} does not exist") print(f"file {json_file} does not exist")
parser.print_help() parser.print_help()
exit() exit()
plines = model_from_json(json_path) plines, error_collector = model_from_json(json_path)
# Allgemeine Config laden # Allgemeine Config laden
config = configparser.ConfigParser(allow_no_value=True, delimiters=("=")) config = configparser.ConfigParser(allow_no_value=True, delimiters=("="))
@@ -931,4 +999,10 @@ if __name__ == '__main__':
# 5. Excel schreiben # 5. Excel schreiben
excel_path = os.path.join(work_dir, args.excel) excel_path = os.path.join(work_dir, args.excel)
write_excel_from_json(plines, sens2cable, excel_path) write_excel_from_json(plines, sens2cable, excel_path, error_collector)
# 6. Optionale Fehlerdatei schreiben
if error_collector.has_errors():
basename = Path(args.excel).stem
error_filename = f"{basename}_errors.json"
error_collector.write_errorfile(Path(work_dir), error_filename)
+81
View File
@@ -0,0 +1,81 @@
"""
ErrorCollector - Gemeinsame Klasse zum Sammeln von Fehlern und Warnungen
Diese Klasse wird von getpositions.py und drawdxf.py verwendet, um Fehler
und Warnungen während der Verarbeitung zu sammeln und zu verwalten.
"""
import json
from pathlib import Path
class ErrorCollector:
"""Sammelt alle Fehler und Warnungen während der Verarbeitung."""
def __init__(self):
self.errors = {}
self.warnings = {}
def add_errors(self, error_dict):
"""Fügt Fehler aus einem Dictionary hinzu."""
for key, value in error_dict.items():
if key in self.errors:
if isinstance(self.errors[key], list) and isinstance(value, list):
self.errors[key].extend(value)
else:
self.errors[key] = [self.errors[key], value]
else:
self.errors[key] = value
def add_warnings(self, warning_dict):
"""Fügt Warnungen aus einem Dictionary hinzu."""
for key, value in warning_dict.items():
if key in self.warnings:
if isinstance(self.warnings[key], list) and isinstance(value, list):
self.warnings[key].extend(value)
else:
self.warnings[key] = [self.warnings[key], value]
else:
self.warnings[key] = value
def has_errors_or_warnings(self):
"""Prüft ob Fehler oder Warnungen vorhanden sind."""
return bool(self.errors) or bool(self.warnings)
def has_errors(self):
"""Prüft ob Fehler vorhanden sind."""
return bool(self.errors)
def get_all_issues(self):
"""Gibt alle Fehler und Warnungen als Dictionary zurück."""
result = {}
if self.errors:
result["errors"] = self.errors
if self.warnings:
result["warnings"] = self.warnings
return result
def write_errorfile(self, work_dir: Path, filename: str):
"""Schreibt Fehlerdatei nur wenn Fehler oder Warnungen vorhanden sind."""
if self.has_errors():
print("Fehler gefunden. Schreibe Error-Datei.")
all_issues = self.get_all_issues()
write_json_file(all_issues, work_dir, filename)
else:
print("Keine Fehler oder Warnungen gefunden. Keine Error-Datei geschrieben.")
def write_json_file(data: dict, out_dir: Path, filename: str) -> None:
"""
Schreibt Daten in eine JSON-Datei.
Args:
data: Dictionary mit zu schreibenden Daten
out_dir: Ausgabeverzeichnis
filename: Dateiname für die JSON-Datei
"""
print("writing data to a json file ...")
outfile = out_dir / filename if isinstance(out_dir, Path) else Path(out_dir) / filename
with open(outfile, 'w', encoding='utf-8') as fh:
json.dump(data, fh, indent=2, ensure_ascii=False, default=str)
print("done")
+2 -56
View File
@@ -11,6 +11,8 @@ from ezdxf.addons import iterdxf
from shapely.geometry import Point from shapely.geometry import Point
from ezdxf.lldxf.const import DXFStructureError from ezdxf.lldxf.const import DXFStructureError
from error_collector import ErrorCollector, write_json_file
""" """
Dieses Programm: Dieses Programm:
@@ -22,62 +24,6 @@ Dieses Programm:
""" """
class ErrorCollector:
"""Sammelt alle Fehler und Warnungen während der Verarbeitung."""
def __init__(self):
self.errors = {}
self.warnings = {}
def add_errors(self, error_dict):
"""Fügt Fehler aus einem Dictionary hinzu."""
for key, value in error_dict.items():
if key in self.errors:
if isinstance(self.errors[key], list) and isinstance(value, list):
self.errors[key].extend(value)
else:
self.errors[key] = [self.errors[key], value]
else:
self.errors[key] = value
def add_warnings(self, warning_dict):
"""Fügt Warnungen aus einem Dictionary hinzu."""
for key, value in warning_dict.items():
if key in self.warnings:
if isinstance(self.warnings[key], list) and isinstance(value, list):
self.warnings[key].extend(value)
else:
self.warnings[key] = [self.warnings[key], value]
else:
self.warnings[key] = value
def has_errors_or_warnings(self):
"""Prüft ob Fehler oder Warnungen vorhanden sind."""
return bool(self.errors) or bool(self.warnings)
def has_errors(self):
"""Prüft ob Fehlervorhanden sind."""
return bool(self.errors)
def get_all_issues(self):
"""Gibt alle Fehler und Warnungen als Dictionary zurück."""
result = {}
if self.errors:
result["errors"] = self.errors
if self.warnings:
result["warnings"] = self.warnings
return result
def write_errorfile(self, work_dir: Path, filename: str):
"""Schreibt Fehlerdatei nur wenn Fehler oder Warnungen vorhanden sind."""
if self.has_errors():
print("Fehler gefunden. Schreibe Error-Datei.")
all_issues = self.get_all_issues()
write_results(to_json(all_issues), work_dir, filename)
else:
print("Keine Fehler oder Warnungen gefunden. Keine Error-Datei geschrieben.")
def write_results(jsn_results: str, out_dir: Path, filename: str) -> None: def write_results(jsn_results: str, out_dir: Path, filename: str) -> None:
"""Write results to a JSON file.""" """Write results to a JSON file."""
print("writing results to a json file ...") print("writing results to a json file ...")
+1 -7
View File
@@ -65,11 +65,5 @@
] ]
] ]
}, },
"not_found": { "warnings": {}
"missing_distributors": [],
"missing_sensors": [],
"missing_tunnel": [],
"missing_attributes": {}
},
"double_ids": {}
} }
+1 -4
View File
@@ -1,8 +1,5 @@
{ {
"errors": { "errors": {
"missing_distributors": [],
"missing_sensors": [],
"missing_tunnel": [],
"overdefined_tunnel": [ "overdefined_tunnel": [
"TUNNEL2" "TUNNEL2"
] ]
@@ -12,4 +9,4 @@
"BX0101": "Nur ein Block und/oder fehlende Attribute: dict_keys(['A', 'B', 'C', 'ARTINR', 'BESCHR', 'MENGE', 'POSITION', 'GRUPPE', 'ETIKETTE', 'AUFLOESE', 'pos'])" "BX0101": "Nur ein Block und/oder fehlende Attribute: dict_keys(['A', 'B', 'C', 'ARTINR', 'BESCHR', 'MENGE', 'POSITION', 'GRUPPE', 'ETIKETTE', 'AUFLOESE', 'pos'])"
} }
} }
} }
+2 -6
View File
@@ -280,13 +280,9 @@
] ]
] ]
}, },
"not_found": { "warnings": {
"missing_distributors": [],
"missing_sensors": [],
"missing_tunnel": [],
"missing_attributes": { "missing_attributes": {
"BX0101": "Nur ein Block und/oder fehlende Attribute: dict_keys(['A', 'B', 'C', 'ARTINR', 'BESCHR', 'MENGE', 'POSITION', 'GRUPPE', 'ETIKETTE', 'AUFLOESE', 'pos'])" "BX0101": "Nur ein Block und/oder fehlende Attribute: dict_keys(['A', 'B', 'C', 'ARTINR', 'BESCHR', 'MENGE', 'POSITION', 'GRUPPE', 'ETIKETTE', 'AUFLOESE', 'pos'])"
} }
}, }
"double_ids": {}
} }
+1 -3
View File
@@ -599,7 +599,5 @@
"errors_tunnels": [], "errors_tunnels": [],
"errors_dists_not_in_layout": [], "errors_dists_not_in_layout": [],
"errors_sensors_not_in_layout": [], "errors_sensors_not_in_layout": [],
"errors_missing_attributes": { "errors_missing_attributes": {}
"BX0101": "Nur ein Block und/oder fehlende Attribute: dict_keys(['A', 'B', 'C', 'ARTINR', 'BESCHR', 'MENGE', 'POSITION', 'GRUPPE', 'ETIKETTE', 'AUFLOESE', 'pos'])"
}
} }
+2 -6
View File
@@ -328,13 +328,9 @@
] ]
] ]
}, },
"not_found": { "warnings": {
"missing_distributors": [],
"missing_sensors": [],
"missing_tunnel": [],
"missing_attributes": { "missing_attributes": {
"BX0101": "Nur ein Block und/oder fehlende Attribute: dict_keys(['A', 'B', 'C', 'ARTINR', 'BESCHR', 'MENGE', 'POSITION', 'GRUPPE', 'ETIKETTE', 'AUFLOESE', 'pos'])" "BX0101": "Nur ein Block und/oder fehlende Attribute: dict_keys(['A', 'B', 'C', 'ARTINR', 'BESCHR', 'MENGE', 'POSITION', 'GRUPPE', 'ETIKETTE', 'AUFLOESE', 'pos'])"
} }
}, }
"double_ids": {}
} }
+1 -3
View File
@@ -599,7 +599,5 @@
"errors_tunnels": [], "errors_tunnels": [],
"errors_dists_not_in_layout": [], "errors_dists_not_in_layout": [],
"errors_sensors_not_in_layout": [], "errors_sensors_not_in_layout": [],
"errors_missing_attributes": { "errors_missing_attributes": {}
"BX0101": "Nur ein Block und/oder fehlende Attribute: dict_keys(['A', 'B', 'C', 'ARTINR', 'BESCHR', 'MENGE', 'POSITION', 'GRUPPE', 'ETIKETTE', 'AUFLOESE', 'pos'])"
}
} }
+5
View File
@@ -327,5 +327,10 @@
0.0 0.0
] ]
] ]
},
"warnings": {
"missing_attributes": {
"BX0101": "Nur ein Block und/oder fehlende Attribute: dict_keys(['A', 'B', 'C', 'ARTINR', 'BESCHR', 'MENGE', 'POSITION', 'GRUPPE', 'ETIKETTE', 'AUFLOESE', 'pos'])"
}
} }
} }
+1 -7
View File
@@ -290,11 +290,5 @@
] ]
] ]
}, },
"not_found": { "warnings": {}
"missing_distributors": [],
"missing_sensors": [],
"missing_tunnel": [],
"missing_attributes": {}
},
"double_ids": {}
} }
+330
View File
@@ -0,0 +1,330 @@
{
"sensors": {},
"schaltschrank_elemente": {
"UZ0309": {
"A": "0",
"B": "UZ0309",
"C": "86623213910015374844",
"ARTINR": "790000057",
"BESCHR": "Sirius act Tableau 4 F",
"MENGE": "1",
"POSITION": "0",
"GRUPPE": "9",
"ETIKETTE": "0",
"AUFLOESE": "N",
"pos": [
960.2,
1991.7
]
},
"SF0080@3": {
"IO": "SF0080",
"ID": "9999",
"VERW": "IPB-YE-NO",
"BEZEICHNUNG": "Betriebshalt UZ0309",
"KENNZEICHNUNG": "=A01+UH03-KF1DI5",
"TEXT-D": "Betriebshalt",
"TEXT-E": "Area stop",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
1134.1,
1176.3
]
},
"SF0081@3": {
"IO": "SF0081",
"ID": "9999",
"VERW": "IPB-BU-NO",
"BEZEICHNUNG": "Reset UZ0309",
"KENNZEICHNUNG": "=A01+UH03-KF1DI5",
"TEXT-D": "Reset ",
"TEXT-E": "Reset ",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
1134.1,
906.3
]
},
"SF0471@3": {
"IO": "SF0471",
"ID": "9999",
"VERW": "PDT-NC-1",
"BEZEICHNUNG": "Not Halt Kanal 1 UZ0309",
"KENNZEICHNUNG": "=A01+UH03-KF1FDI7",
"TEXT-D": "Not-Halt Kanal 1",
"TEXT-E": "E-Stop Canal 1",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
1134.1,
606.1
]
},
"SF0475@3": {
"IO": "SF0475",
"ID": "9999",
"VERW": "PDT-NC-2",
"BEZEICHNUNG": "Not Halt Kanal 2 UZ0309",
"KENNZEICHNUNG": "=A01+UH03-KF1FDI7",
"TEXT-D": "Not-Halt Kanal 2",
"TEXT-E": "E-stop Canal 2",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
1134.1,
336.1
]
},
"PF0081@3": {
"IO": "PF0081",
"ID": "9999",
"VERW": "IPB-BU-LED",
"BEZEICHNUNG": "Reset UZ0309",
"KENNZEICHNUNG": "=A01+UH03-KF1DQ5",
"TEXT-D": "",
"TEXT-E": "",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
1876.6,
906.3
]
},
"PF0080@3": {
"IO": "PF0080",
"ID": "9999",
"VERW": "IPB-BN-LED",
"BEZEICHNUNG": "Betriebsbereit UZ0309",
"KENNZEICHNUNG": "=A01+UH03-KF1DQ5",
"TEXT-D": "Betriebsbereit",
"TEXT-E": "Ready for use",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
1876.6,
1446.3
]
},
"SF0000@3": {
"IO": "SF0000",
"ID": "9999",
"VERW": "PB-BK-NC",
"BEZEICHNUNG": "DT Anlage Aus ",
"KENNZEICHNUNG": "=A01+UH03-KF1DI1",
"TEXT-D": "DT Anlage Aus",
"TEXT-E": "PB System Off",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
1468.0,
7509.3
]
},
"SF0001@3": {
"IO": "SF0001",
"ID": "9999",
"VERW": "IPB-GN-NO",
"BEZEICHNUNG": "LDT Anlage Ein",
"KENNZEICHNUNG": "=A01+UH03-KF1DI1",
"TEXT-D": "LDT Anlage Ein",
"TEXT-E": "IPB system On",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
1468.0,
7239.3
]
},
"SF0002@3": {
"IO": "SF0002",
"ID": "9999",
"VERW": "IPB-CL-NO",
"BEZEICHNUNG": "LDT Start nach Störung",
"KENNZEICHNUNG": "=A01+UH03-KF1DI1",
"TEXT-D": "LDT Start nach Störung",
"TEXT-E": "IPB Start after Trouble",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
1468.0,
6969.3
]
},
"SF0003@3": {
"IO": "SF0003",
"ID": "9999",
"VERW": "PB-WH-NO",
"BEZEICHNUNG": "LM Lampentest",
"KENNZEICHNUNG": "=A01+UH03-KF1DI1",
"TEXT-D": "LM Lampentest",
"TEXT-E": "IL Lamp test",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
1468.0,
6699.3
]
},
"SF0400@3": {
"IO": "SF0400",
"ID": "9999",
"VERW": "PDT-NC-1",
"BEZEICHNUNG": "Not Halt Kanal 1 UH03",
"KENNZEICHNUNG": "=A01+UH03-KF1FDI6",
"TEXT-D": "Not-Halt Kanal 1",
"TEXT-E": "E-Stop Canal 1",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
1468.0,
5079.3
]
},
"SF0404@3": {
"IO": "SF0404",
"ID": "9999",
"VERW": "PDT-NC-2",
"BEZEICHNUNG": "Not Halt Kanal 2 UH03",
"KENNZEICHNUNG": "=A01+UH03-KF1FDI6",
"TEXT-D": "Not-Halt Kanal 2",
"TEXT-E": "E-stop Canal 2",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
1468.0,
4809.3
]
},
"PF0001@3": {
"IO": "PF0001",
"ID": "9999",
"VERW": "IL-YE-LED",
"BEZEICHNUNG": "LDT Anlage Ein",
"KENNZEICHNUNG": "=A01+UH03-KF1DQ1",
"TEXT-D": "",
"TEXT-E": "",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
2210.5,
7239.3
]
},
"PF0002@3": {
"IO": "PF0002",
"ID": "9999",
"VERW": "IL-YE-LED",
"BEZEICHNUNG": "LDT Start nach Störung",
"KENNZEICHNUNG": "=A01+UH03-KF1DQ1",
"TEXT-D": "",
"TEXT-E": "",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
2210.5,
6969.3
]
},
"PF0003@3": {
"IO": "PF0003",
"ID": "9999",
"VERW": "IL-YE-LED",
"BEZEICHNUNG": "LM Druckluft fehlt",
"KENNZEICHNUNG": "=A01+UH03-KF1DQ1",
"TEXT-D": "LM Druckluft fehlt",
"TEXT-E": "IL compressed air missing",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
2210.5,
6159.3
]
},
"PF0004@3": {
"IO": "PF0004",
"ID": "9999",
"VERW": "IL-YE-LED",
"BEZEICHNUNG": "LM Motorschutz hat ausgelöst",
"KENNZEICHNUNG": "=A01+UH03-KF1DQ1",
"TEXT-D": "LM Motorschutz hat ausgelöst",
"TEXT-E": "IL motor protection tripped",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
2210.5,
5889.3
]
},
"PF0005@3": {
"IO": "PF0005",
"ID": "9999",
"VERW": "IL-YE-LED",
"BEZEICHNUNG": "LM Sicherung hat ausgelöst",
"KENNZEICHNUNG": "=A01+UH03-KF1DQ1",
"TEXT-D": "LM Sicherung hat ausgelöst",
"TEXT-E": "IL fuse has tripped",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
2210.5,
5619.3
]
},
"PF0006@3": {
"IO": "PF0006",
"ID": "9999",
"VERW": "IL-RD-LED",
"BEZEICHNUNG": "LM Brandfall",
"KENNZEICHNUNG": "=A01+UH03-KF1DQ1",
"TEXT-D": "LM Brandfall",
"TEXT-E": "IL Störung Brandschutztüren",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
2210.5,
5349.3
]
},
"PF0000@3": {
"IO": "PF0000",
"ID": "9999",
"VERW": "IL-YE-LED",
"BEZEICHNUNG": "LM Störung ",
"KENNZEICHNUNG": "=A01+UH03-KF1DQ1",
"TEXT-D": "LM Störung",
"TEXT-E": "IL Trouble",
"TEXT-ES": "",
"TEXT-F": "",
"SPS": "3",
"pos": [
2210.5,
6429.3
]
}
},
"mappings": {},
"distributors": {},
"tunnels": {},
"racks": {},
"warnings": {}
}
+11
View File
@@ -0,0 +1,11 @@
{
"kabel": [],
"rack_geometry": {},
"errors_routing": [],
"errors_sensors": [],
"errors_dists": [],
"errors_tunnels": [],
"errors_dists_not_in_layout": [],
"errors_sensors_not_in_layout": [],
"errors_missing_attributes": {}
}