Das System erstellt Digitale Produktpässe (DPP) für Beton-Fertigelemente eines Hyperloop-Prototyps. Es besteht aus vier Schichten:
┌─────────────────────────────────────────────────────────┐
│ Arduino (Sensoren + RFID + Servo) │
│ ↕ Seriell (USB, 9600 Baud, JSON) │
│ Python GUI (Tkinter) – Produktionssteuerung │
│ ↕ Git Push / GitHub Pages │
│ Web-Viewer (viewer.html, batch/index.html) │
│ ↕ ifcopenshell │
│ IFC-Integration (Pset-Schreiber) │
└─────────────────────────────────────────────────────────┘
DPP-EUROTUBE/
├── index.html ← Landing Page (GitHub Pages)
├── README.md
├── prototyp_final/
│ ├── hyperloop_dpp.py ← Haupt-Python-Skript (GUI + Logik)
│ ├── hyperloop_qr_prep.py ← QR-Label-Generator (PDF)
│ ├── hyperloop_dpp_combined/
│ │ └── hyperloop_dpp_combined.ino ← Arduino-Sketch (Final)
│ └── qr_labels/
│ ├── labels.pdf ← Druckbare QR-Etiketten (A4)
│ └── prepared.json ← Manifest der generierten SNs
├── hardware/
│ ├── 3d_print/ ← STL-Dateien (Schalung + Tisch)
│ │ ├── EuroTube_Mold_Left.stl / _V2.stl
│ │ ├── EuroTube_Mold_Right.stl / _V2.stl
│ │ ├── EuroTube_Table.stl / _V2.stl
│ │ └── EuroTube_Tubesegment.stl
│ └── arduino/
│ ├── sketch.ino ← Arduino-Sketch (Wokwi)
│ ├── diagram.json ← Elektronisches Schema (Wokwi)
│ ├── libraries.txt ← Bibliotheksliste
│ ├── wokwi-project.txt ← Wokwi-Projekt-Link
│ └── komponenten.md ← Komponentenliste
├── passports/
│ ├── viewer.html ← Einzel-DPP Viewer (Web)
│ └── *.jsonld ← Generierte Segment-Passports
├── batch/
│ ├── index.html ← Batch-Viewer + Scanner (Web)
│ └── *.jsonld ← Generierte Batch-Passports
├── IFC/
│ ├── IP3.ifc ← Quell-IFC-Modell
│ ├── add_dpp_links.py ← V1: DPP-URLs ins IFC
│ ├── add_dpp_data.py ← V2: Alle DPP-Daten ins IFC
│ ├── IP3_DPP_Batchlinks.ifc ← Output V1
│ └── IP3_DPP_abgefüllt.ifc ← Output V2
├── Handlungsempfehlungen/
│ ├── handlungsempfehlungen.html ← Viewer (GitHub Pages)
│ └── Handlungsempfehlungen_DPP.pdf ← PDF
└── .gitignore
| Kategorie | Komponente |
|---|---|
| Mikrocontroller | Arduino Uno |
| Module und Sensoren | RFID-Modul RC522 |
| DHT22 / DHT11 | |
| Eingabe und Ausgabe | 2 Servomotoren |
| Drucktaster | |
| Verkabelung und Prototyping | Steckbrett, Widerstand, Jumperkabel |
| Stromversorgung | Batteriepack (4 × 1.5 V) |
Das Schaltschema ist als Wokwi-Simulation verfügbar:
hardware/arduino/diagram.json – importierbar unter https://wokwi.com/projects/461746891808954369
Die physische Schalung (SMF) wurde als Prototyp gedruckt. Die STL-Dateien liegen unter hardware/3d_print/:
| Datei | Beschreibung |
|---|---|
EuroTube_Mold_Left.stl / _V2.stl |
Linke Schalungshälfte |
EuroTube_Mold_Right.stl / _V2.stl |
Rechte Schalungshälfte |
EuroTube_Table.stl / _V2.stl |
Produktionstisch |
EuroTube_Tubesegment.stl |
Röhrensegment-Modell |
Steuert die physische Hardware: DHT11-Sensor (Temperatur/Feuchtigkeit), Servo (Schalung öffnen/schliessen), MFRC522 (RFID/NFC-Leser).
| Komponente | Pin |
|---|---|
| DHT11 | 2 |
| Taster | 3 (INPUT_PULLUP) |
| Servo | 6 |
| RFID RST | 9 |
| RFID SS | 10 |
| SPI | 11, 12, 13 (Standard) |
Eingabe (Python → Arduino):
C– Schalung schliessen, Messung startenO– Schalung öffnen, Messung stoppen
Ausgabe (Arduino → Python):
{"type":"boot","msg":"System bereit (DHT+Servo+RFID)"}
{"type":"event","event":"cmd_start"}
{"type":"sensor","grund":"periodic","temp":22.5,"hum":58.0,"servo":5}
{"type":"event","event":"cmd_stopp"}
{"type":"rfid","url":"https://w3id.org/hyperloop-dpp/01/09999000000001/21/1234567890"}
{"type":"rfid_error","msg":"Auth fehlgeschlagen"}- Liest NDEF-URL-Records von MIFARE Classic 1K Karten
- Sektor 1 (Blöcke 4–6) + Sektor 2 (Blöcke 8–10) = 96 Bytes
- Authentifizierung mit NFC-Forum-Key:
D3 F7 D3 F7 D3 F7 - NDEF-Prefix
0x04=https://, Terminator0xFE= Ende - Nach erfolgreichem Scan wird
rfidAktiv = falsegesetzt (einmaliger Scan pro Zyklus)
- Taster oder
C-Befehl → Schalung schliesst, Sensoraufzeichnung startet - Alle 2 Sekunden wird
{"type":"sensor",...}gesendet - Taster oder
O-Befehl → Schalung öffnet, RFID-Scan wird aktiviert - RFID-Karte erkannt → URL wird gesendet, Scan deaktiviert
Desktop-Anwendung (Tkinter) zur Produktionssteuerung. Empfängt Sensordaten vom Arduino, erstellt JSON-LD Passports und pusht sie via Git auf GitHub Pages.
pip install pyserial qrcode[pil]
Optional (für Kamera-QR-Scan): pip install opencv-python pyzbar
| Konstante | Wert | Beschreibung |
|---|---|---|
PORT |
COM7 |
Serieller Port des Arduino |
BAUD |
9600 |
Baudrate |
W3ID_BASE |
https://w3id.org/hyperloop-dpp |
Basis-URI für GS1 Digital Links |
GTIN |
09999000000001 |
GS1 GTIN-14 des Produkts |
GITHUB_PAGES |
https://DPPIP.github.io/DPP-EUROTUBE |
GitHub Pages URL |
GITHUB_REPO |
C:/Users/david/Documents/DPP-EUROTUBE |
Lokaler Pfad zum Git-Repo |
BSDD_BASE |
.../HYPER-DPP/0.6 |
bSDD Datenkatalog Version |
BETONSORTE |
C25/30 |
Standardwert (überschreibbar in GUI) |
HERSTELLUNGSORT |
Koblenz |
Standardwert (überschreibbar in GUI) |
Extrahiert die Seriennummer aus einem GS1 Digital Link URI:
https://w3id.org/.../21/1234567890→1234567890https://w3id.org/.../10/4521→45211234567890→1234567890
Generiert das JSON-LD Dokument für ein Segment. Verwendet bSDD 0.6 Property-Namen:
| JSON-LD Key | Inhalt |
|---|---|
bsdd:SegmentID |
Seriennummer |
bsdd:StrengthClass |
Betonsorte (aus GUI-Eingabe) |
bsdd:AssemblyPlace |
Herstellungsort (aus GUI-Eingabe) |
bsdd:ManufactoringDate |
ISO-Zeitstempel |
bsdd:ReferenceEnvironmentTemperature |
Durchschnittstemperatur in °C |
bsdd:ReferenceAirRelativeHumidity |
Durchschnittliche Luftfeuchtigkeit in % |
bsdd:Schalungsdauer |
Dauer in Stunden (Minuten / 60) |
bsdd:Status |
Aktiv |
git pull --rebase --autostash(verhindert Konflikte)- Dateien ins Repo kopieren
git add,git commit,git push
Erstellt JSON-LD, speichert lokal unter passports/{sn}.jsonld, pusht via Git.
Nach Produktionsstopp öffnet sich ein Dialog mit:
- Kamera-Preview (OpenCV + pyzbar) – erkennt QR-Codes automatisch
- RFID-Callback – Arduino sendet URL, Dialog reagiert automatisch
- Manuelles Eingabefeld – Fallback für USB-Scanner
- Duplikatprüfung – HEAD-Request auf GitHub Pages, verhindert doppelte Vergabe
Polling-Funktion (alle 100 ms via root.after). Verarbeitet JSON-Nachrichten vom Arduino:
cmd_start/system_start→ Aufzeichnung starten, Sensor-Arrays leerensensor→ Temperatur/Feuchtigkeit sammelnrfid→ ID extrahieren, an Scan-Dialog weiterleitencmd_stopp/system_stopp→ Median berechnen, Scan-Dialog öffnen
- Statusanzeige: Schalung offen/geschlossen, aktueller Zustand
- Eingabefelder: Betonsorte und Herstellungsort (editierbar, Standardwerte)
- Buttons: "Schliessen & Start" / "Öffnen & Stopp"
- DPP-Liste: Scrollbare Liste aller erstellten Passports (Doppelklick öffnet im Browser)
- URI-Label: Klickbar, öffnet den zuletzt erstellten DPP im Browser
Generiert druckbare QR-Code-Etiketten als A4-PDF. Jedes Label enthält eine eindeutige GS1 Digital Link URI.
pip install qrcode[pil] reportlab
| Konstante | Wert |
|---|---|
COUNT |
11 (eindeutige SNs) |
COLS × ROWS |
3 × 8 = 24 Plätze |
| Labels total | 13 (11 einmalig + 2 Duplikate) |
qr_labels/labels.pdf– A4, randlos, QR 90° gedrehtqr_labels/prepared.json– Manifest[{id, uri, used}, ...]
┌──────────────────────────────────┐
│ [QR 90°] Digital Product Passport│
│ https://w3id.org/.../ │
│ 01/GTIN/21/ │
│ 1234567890 (fett) │
└──────────────────────────────────┘
10-stellig, zufällig generiert (random.randint(1000000000, 9999999999)). Die ersten zwei SNs werden doppelt gedruckt (für Duplikat-Tests).
Rendert ein einzelnes Segment-DPP im Browser. Wird auf GitHub Pages gehostet, Daten werden per Fetch aus den .jsonld-Dateien geladen.
?sn=1234567890– Seriennummer des Segments (Pflicht)?single=1– Batch-Redirect unterdrücken
snaus URL lesen- Fetch
passports/{sn}.jsonldvon GitHub Pages - Wenn
@type=HyperloopBatch→ Redirect zubatch/index.html - Wenn
bsdd:BatchIDvorhanden und kein?single=1→ Redirect zum Batch - Render: 7 Felder (Betonsorte, Herstellungsort, Datum, Temperatur, Schalungsdauer, Status, Luftfeuchtigkeit)
- QR-Code generieren (qrcodejs)
| Feld | JSON-LD Key |
|---|---|
| Betonsorte | bsdd:StrengthClass |
| Herstellungsort | bsdd:AssemblyPlace |
| Herstellungsdatum | bsdd:ManufactoringDate.@value |
| Herstellungstemperatur | bsdd:ReferenceEnvironmentTemperature.@value |
| Dauer in der Schalung | bsdd:Schalungsdauer.@value |
| Status | bsdd:Status |
| Luftfeuchtigkeit | bsdd:ReferenceAirRelativeHumidity.@value |
Zwei Modi in einer Datei:
- Scanner-Modus (
index.htmlohne Parameter): QR-Scanner zum Erstellen neuer Batches - Batch-Ansicht (
?batch=ID): Anzeige eines bestehenden Batches
- Kamera-basierter QR-Scanner (html5-qrcode)
- 5 Segmente scannen → "Batch erstellen"
- Erstellt
batch/{batchId}.jsonldvia GitHub API (Token im localStorage) - Schreibt
bsdd:BatchIDin jedes Segment-JSONLD zurück - Duplikatschutz: Segment mit existierender BatchID wird abgelehnt
- Titel: "Batch Röhrensegment 10 M"
- Batch-Karte: Batch-ID, Verbindungsdatum
- Bestandteile: Pro Segment → Bauteiltyp, Betonsorte, Herstellungsort, Temperatur, Schalungsdauer
- Status-Karte: Verbunden/offen, Einbaudatum
- Buttons: Link kopieren, JSON-LD anzeigen
{
"@type": ["dpp:DigitalProductPassport", ".../HyperloopBatch"],
"bsdd:Batch_ID": "4873316459",
"bsdd:Verbindungsdatum": {"@value": "2026-04-15T10:35:24"},
"bsdd:VerlinkungBauteile": ["https://w3id.org/.../21/SN1", "..."],
"bsdd:Status": "Verbunden",
"bsdd:Material": "SikaProof",
"bsdd:Spannstahlsorte": "St1570",
"bsdd:Klebertyp": "PCI"
}Schreibt DPP-Informationen in ein bestehendes IFC-Modell (IP3.ifc) via ifcopenshell.
pip install ifcopenshell
IfcElementAssembly "Batch" (Röhrensegment 10m = 5 Betonelemente)
├── IfcBuildingElementProxy "Betonsegment_2m10"
├── IfcBuildingElementProxy "Betonsegment_2m11"
├── IfcBuildingElementProxy "Betonsegment_2m12"
├── IfcBuildingElementProxy "Betonsegment_2m13"
├── IfcBuildingElementProxy "Betonsegment_2m14"
├── IfcCovering "Beschichtung"
├── IfcReinforcingBar "Spannstahl" (×5)
└── IfcFastener "Kleber" (×4)
Schreibt nur DPP-URLs in ein einziges Pset:
| Element | Pset | Property | Wert |
|---|---|---|---|
| IfcElementAssembly | ePset_DigitalProductPassport |
URL |
Batch-Viewer-Link |
| IfcBuildingElementProxy | ePset_DigitalProductPassport |
URL |
GS1 Digital Link URI |
Schreibt alle DPP-Daten gemäss IFC-Mapping in mehrere Psets:
IfcElementAssembly (Batch):
| Pset | Properties |
|---|---|
ePset_DigitalProductPassport |
URL, Batch_ID, Verbindungsdatum, Status, Einbaudatum |
IfcBuildingElementProxy (Segment):
| Pset | Properties |
|---|---|
ePset_DigitalProductPassport |
URL |
Pset_ConcreteElementGeneral |
StrengthClass |
Pset_ManufacturerTypeInformation |
AssemblyPlace |
Pset_ManufacturerOccurrence |
ManufactoringDate |
Pset_EnvironmentalCondition |
ReferenceEnvironmentTemperature, ReferenceAtRelativeHumidity |
Pset_Herstellung |
Schalungsdauer, Status |
https://w3id.org/hyperloop-dpp/01/{GTIN}/21/{Serial} → Segment
https://w3id.org/hyperloop-dpp/01/{GTIN}/10/{BatchID} → Batch
- AI 01 = GTIN-14 (
09999000000001) - AI 21 = Seriennummer (SGTIN, Segment-Ebene)
- AI 10 = Losnummer (LGTIN, Batch-Ebene)
- W3ID leitet via
.htaccessauf GitHub Pages weiter (PR pending bei perma-id/w3id.org)
1. Schalung schliessen (Button/Taster)
→ Arduino: Servo schliesst, Sensormessung startet
2. Sensordaten sammeln (alle 2s)
→ Arduino sendet JSON → Python sammelt Temperatur + Feuchtigkeit
3. Schalung öffnen (Button/Taster)
→ Arduino: Servo öffnet, RFID-Scan aktiviert
→ Python: Median berechnen, Scan-Dialog öffnen
4. QR-Code / RFID scannen
→ Kamera, RFID oder manuell → Segment-ID extrahiert
→ Duplikatprüfung (HEAD-Request auf GitHub Pages)
5. DPP erstellen und publizieren
→ JSON-LD generieren → lokal speichern
→ git pull --rebase → git add → git commit → git push
→ GitHub Pages aktualisiert automatisch
6. Batch erstellen (batch/index.html)
→ 5 Segmente scannen → Batch-JSONLD via GitHub API erstellen
→ BatchID in jedes Segment-JSONLD zurückschreiben
7. IFC-Integration (optional)
→ add_dpp_links.py oder add_dpp_data.py
→ Schreibt URLs / Daten in IFC-Psets
- Fehlerbehandlung:
except Exception: passin der seriellen Leseroutine schluckt Fehler still. Bei Produktionseinsatz sollte Logging ergänzt werden. - Blockierender HTTP-Call: Die Duplikatprüfung (
urllib.request.urlopen) blockiert kurzzeitig die GUI. Bei schlechtem Netzwerk kann dies zu Verzögerungen führen. - Git-Push: Verwendet
subprocessfür Git-Befehle. Bei Merge-Konflikten kann der Push fehlschlagen (wird in Konsole ausgegeben). - Kamera-Freigabe: Bei unerwartetem Schliessen des Scan-Dialogs kann die Kamera-Ressource blockiert bleiben.
- Prototyp-Charakter: Das Skript ist für den Laborbetrieb an der FHNW konzipiert, nicht für industriellen Einsatz.