#import "@preview/diatypst:0.9.0": * #import sym: arrow #set text(font: "TeX Gyre Adventor") #show heading.where(level: 3): it =>[ #block(it.body) ] #show: slides.with( title: "Abfahrtsanzeiger Hacken 2.0", date: "17.05.2026", authors: ("Christian Seiler, flop"), // Optional (for more see docs at https://mdwm.org/diatypst/) ratio: 16/9, layout: "medium", title-color: blue.darken(30%), toc: false, ) = Was bisher geschah == Erstkontakt mit den Stadtwerken (Februar 2023) #figure( grid( columns: 2, gutter: 2mm, image("stadtwerke1.PNG", width: auto), image("stadtwerke2.PNG", width: auto), ) ) == Anlieferung der Anzeiger (Oktober 2023) #figure( grid( columns: 2, gutter: 2mm, image("36cbc47d30c88e94.png", width: auto), image("7c3f89ceae88b388.jpg", width: auto), ) ) == Reverse Engineering Versuche #figure( grid( columns: 2, gutter: 2mm, image("06229735a9d36e8c.jpg", width: auto), image("e993d285f6279cdd.jpg", width: auto), ) ) == Durchbruch in Entropia (April 2025) #align(center)[ #image("entropia.jpg", width: auto) ] == Erster Einsatz auf der GPN 2025 #grid( columns: 2, gutter: 15mm, "\n- ESP32\n- Embedded Rust\n- Daten aus Pretalx", image("0c914abfddc86330.png", width: auto), ) == Weitere Einsätze: TDF4 & Cyborx #figure( grid( columns: 2, gutter: 2mm, image("ae85ca78a01cae0d.png", width: auto), image("a05077ee7e192d99.jpg", width: auto), ) ) = Erste Weiterentwicklung Hardware & Firmware == Datenformat 1.0 Binärformat, das aus einer Liste von Elementen besteht, die gezeichnet werden sollen. === Features - Bilder - Animationen - Scrollende Bilder (vorgerenderter Lauftext) === Bilddaten - Koordinaten fangen bei (0, 0) an - 1 bit pro Pixel - Pixel Index: $n(x, y) = y * W + x$ - Byte Index: $B(x, y) = floor(n(x, y) / 8)$ - Bit Index: $b(x, y) = n(x, y) mod 8$ == Spaß am 39C3 (Dezember 2025) #grid( columns: 2, gutter: 15mm, image("IMG_20251226_173113.jpg", width: auto), [ - Mikrocontroller + Firmware - Basierend auf Entropia-Arbeit (Rust, ESP32) - Modifikationen zum Rendering des Datenformats - Busanzeiger Paint (Webinterface) - Zeichnen mit verschiedenen Pixelgrößen - Rudimentäres Textrendering - Importieren von Bildern/GIFs - Erstellung von Animationen - "Vibe-Coding for the win" - Round-Robin Bilder / Animationen vom Server - CLI-Tool zur Vorschau (#arrow.r Demo) ] ) == Custom PCB 1.0 #grid( columns: 2, gutter: 15mm, image("IMG_20260309_214103.jpg", width: auto), [ - LVDS-Transceiver auf Platine (#arrow.r altes Mainboard nicht mehr benötigt) - Anschluss per 8p8c ("RJ45") Stecker (#arrow.r kein Custom Lötjub) - Eigene Spannungsversorgung für Mikrocontroller - Alternativer Anschluss für Seeed ESP32-S3 (kleineres Format) - Funktioniert ohne Firmware-Änderung auf bestehendem Mikrocontroller #emoji.face ] ) #align(center)[ #image("erste_funktion.jpeg", width: 60%) ] #align(center)[ #image("erstes_logo1.jpeg", width: auto) ] #grid( columns: 2, gutter: 15mm, image("alte_platine.jpeg", width: auto), [ === Not Everything is Perfect #emoji.face.sad - PIN-Reihe für alte Mikros nicht korrekt - Stromversorgung für Seeed ESP32S3 nicht korrekt - Bohrlöcher falsch platziert - Falsche LVDS-Polarität === Learnings - Prototyp-Platine war gute Testing-Platform - Aber: konzentrieren auf einen Mikrocontroller (#arrow.r Seeed ESP32-S3, da 8 MiB SRAM und sehr klein und günstig) - Kleinere Platine wäre besser, v.a. wenn mehr produziert werden sollen ] ) = Let's Do it All Again == Custom PCB #grid( columns: 2, gutter: 5mm, image("neue_platinen.jpeg", width: 8cm), [ - Kleiner Formfaktor (5 cm x 5 cm) - Separate Spannungsversorgungs-Platine (DC-DC) - Hardware-Bugs gefixed (Polarität, Spannungsversorgung) - Nur noch ESP32-S3 - Selbst bestückt - Montage separat per 3D-Druck-Gehäuse - Spannungsversorgung für Displays integriert (optional) ] ) #align(center)[ #image("new_pcb.jpeg", width: auto) ] == Datenformat 2.0 === Neue Features - Auswahl, ob auf Vorder- oder Rückseite angezeigt - Support für Text und Fonts - Support, die aktuelle Uhrzeit anzuzeigen - Zeitspezifische Anzeigen - Animation kurz einblenden - Vorabauslieferung, falls WLAN ausfällt == Firmware (WiP) - Rewrite in C++ - ESP32-Rust-Ökosystem noch zu sehr im Fluss, mehrfach darüber geflucht, dass wir ständig refactorn mussten - ESP32-S3 noch nicht 100% gut supported in Rust - Unfähigkeit von uns, UART0 nicht für Debug-Ausgaben von Rust verwenden zu lassen - Für später: A/B OTA Updates gehen mit ESP-Rust aktuell nicht - Web-Konfiguration - Deckel bleibt zu - Temporärer AP und Web-UI beim ersten Start #arrow.r Web-Konfiguration - Uhrzeit via SNTP == Web-Konfiguration (WiP, vibes) #align(center)[ #image("wifi.png", width: 70%) ] == Web-Editor (WiP, vibes) #align(center)[ #image("webeditor.png", width: auto) ] == Montage #align(center)[ #image("case1.jpeg", width: auto) ] #align(center)[ #image("neue_platine.jpeg", width: 100%) ] = Einsätze == Lichti-Maskenball #align(center)[ #image("abfahrt3.jpeg", width: 90%) ] == TDF5 2026 #align(center)[ #image("saal_bool.jpeg", width: 90%) ] = Ausblick == Ausblick - 23.05. AfD-Verbot jetzt! Demo (Tübingen) - 04.06. GPN 2026 (Karlsruhe) - 04.07. Tübix 2026 (Tübingen) - "First Stable Release" - Automatische pretalx-Integration (serverseitig) - ICS-Integration (serverseitig) - Mehr Busanzeiger flott machen = Danksagung == Danksagung - Stadtwerke Tübingen für die Anzeiger - We stand on the shoulders of giants - Menschen, die das initiale Reverse Engineering gemacht haben - Entropia e.V. - Auslesen des Flash des Original-Mainboards: CC 86 e.V. Heilbronn - Pascal (\@cal) für den Anfang der Slides - Rüdiger für 39c3 Busanzeiger Paint #grid( columns: 2, gutter: 25mm, image("case_closed.jpeg", width: 5cm), [ \ \ \ *Case Closed* ] )