No description
  • Python 72.4%
  • HTML 25.7%
  • Dockerfile 1.9%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-02 13:22:35 +02:00
__pycache__ Add Direction for stops and custom layout 2026-09-02 00:54:16 +02:00
templates Add Custom Color 2026-09-02 13:22:35 +02:00
.dockerignore initial commit 2026-08-22 21:40:57 +02:00
.gitignore initial commit 2026-08-22 21:40:57 +02:00
app.py Add Custom Color 2026-09-02 13:22:35 +02:00
config.ini.example Add Custom Color 2026-09-02 13:22:35 +02:00
docker-compose.yml.example initial commit 2026-08-22 21:40:57 +02:00
Dockerfile initial commit 2026-08-22 21:40:57 +02:00
dvb_api.py Add Direction for stops and custom layout 2026-09-02 00:54:16 +02:00
list_stops.py Add Direction for stops and custom layout 2026-09-02 00:54:16 +02:00
README.md Add Custom Color 2026-09-02 13:22:35 +02:00
requirements.txt initial commit 2026-08-22 21:40:57 +02:00

Straßenbahn-Abfahrtszeiten Dresden (DVB/VVO)

Lokale Python-Webanwendung, die live die Abfahrtszeiten von Straßenbahnen an konfigurierten Haltestellen in Dresden anzeigt.

Die Anwendung nutzt die öffentliche DVB/VVO WebAPI (keine API-Keys erforderlich) und ist für die Anzeige auf E-Ink-Displays optimiert: minimalistisches Design mit nur Schwarz und Weiß.

Installation

  1. Python 3.8+ vorausgesetzt.

Hinweis: config.ini.example dient als Vorlage mit allen verfügbaren Optionen und ihren Standardwerten; sie kann bei Bedarf kopiert werden (cp config.ini.example config.ini).

  1. Abhängigkeiten installieren:
    pip install -r requirements.txt
    

Konfiguration

  1. Haltestellen finden:

    python list_stops.py <Suchbegriff>
    

    Beispiel:

    python list_stops.py Postplatz
    

    Die Ausgabe zeigt die verfügbaren Haltestellen mit ihren exakten Namen. Wähle die korrekte Haltestellenbezeichnung.

  2. config.ini bearbeiten:

    Öffne config.ini und trage die gewünschten Haltestellennamen unter [haltestellen] ein:

    [haltestellen]
    namen = Postplatz, Albertplatz
    

    Du kannst auch lookahead_minutes (Vorlaufzeit für angezeigte Abfahrten) und refresh_seconds (Aktualisierungsintervall) anpassen.

Konfigurationsoptionen in config.ini

Unter [general] können folgende Optionen konfiguriert werden:

  • lookahead_minutes (Standard: 60) — Zeitfenster in Minuten: nur Abfahrten bis zu dieser Zeit in der Zukunft anzeigen.
  • refresh_seconds (Standard: 60) — Seite automatisch aktualisieren in Sekunden.
  • port (Standard: 8080) — Port, auf dem die Web-Anwendung läuft.
  • show_title (Standard: true) — Seitentitel "Straßenbahn-Abfahrtszeiten Dresden" oben anzeigen (true/false).
  • show_clock (Standard: true) — Aktuelle Uhrzeit (im Format HH:MM, Zeitzone Europe/Berlin) oben unter dem Titel anzeigen (true/false). Unabhängig von show_title.
  • theme (Standard: light) — Farbschema: light (schwarzer Text auf weißem Hintergrund), dark (weißer Text auf schwarzem Hintergrund), oder custom (eigene Hintergrund- und Schriftfarben, siehe unten). Bei layout = eink wird theme = custom ignoriert und auf light zurückgefallen, um E-Ink-Kompatibilität zu wahren.
  • custom_bg_color und custom_fg_color (nur relevant wenn theme = custom, Standard: #ffffff und #000000) — Eigene Hintergrund- bzw. Schriftfarbe als Hex-Wert im Format #RRGGBB (z.B. #001133 für dunkelblau, #ffee00 für gelb). Bei ungültigem Format wird theme = custom auf light zurückgefallen.
  • layout (Standard: highres) — Auflösungsmodus mit Auswirkungen auf Schriftgrößen und Abstände. Erlaubte Werte:
    • highres — Optimiert für normale Displays (16px Basisgröße).
    • tablet — Optimiert für Tablets mit größeren Schriften (18px Basisgröße).
    • eink — Optimiert für E-Ink-Displays, setzt die Seite auf eine feste Größe von 800×480px (16px Basisgröße). Bei ungültigem Wert wird automatisch auf highres zurückgegriffen.
    • custom — Eigene feste Seitengröße, kontrolliert über custom_width und custom_height (siehe unten). Schriftgrößen entsprechen highres.
  • custom_width und custom_height (nur relevant wenn layout = custom, Standard je 800 und 480) — Breite und Höhe der Anzeige in Pixel. Bei ungültigen Werten (nicht-numerisch oder ≤0) wird automatisch auf highres zurückgegriffen.
  • max_departures_per_stop (Standard: 6, nur wirksam bei layout = eink oder layout = custom) — Begrenzt die Anzahl der pro Haltestellen-Spalte gerenderten Abfahrten. Verhindert, dass der Inhalt die feste Höhe übersteigt und durch overflow: hidden abgeschnitten wird. Hat keine Auswirkung bei layout = highres oder layout = tablet, da diese nicht auf eine feste Höhe begrenzt sind.

Zusätzlich kann der optionale Abschnitt [richtungen] konfiguriert werden:

  • Richtungsfilter — Für jede Haltestelle und Linie kann eine bestimmte Richtung vorgegeben werden. Format: Haltestellenname = Linie:Richtung, Linie:Richtung, ...
    • Beispiel: Postplatz = 1:Prohlis, 4:Radebeul West zeigt für Linie 1 an dieser Haltestelle nur Züge mit Richtung "Prohlis" an.
    • Linien, die nicht angegeben sind, zeigen weiterhin alle Richtungen.
    • Der gesamte Abschnitt ist optional — fehlt er, ändert sich nichts.
    • Tipp: Nutze python list_stops.py --richtungen <exakter Haltestellenname>, um die verfügbaren Richtungen für eine Haltestelle anzuzeigen.

URL-Parameter

Die Anwendung unterstützt URL-Parameter zum Überschreiben von Konfigurationsoptionen pro Aufruf (ohne dauerhafte Änderungen an config.ini). Diese Parameter haben Vorrang vor den Werten in config.ini:

  • ?theme=light|dark|custom — Überschreibt theme aus config.ini für den aktuellen Aufruf.
    • Beispiel: http://localhost:8080/?theme=dark aktiviert Dark Mode für diesen Aufruf.
    • theme=custom aktiviert benutzerdefinierte Farben (siehe ?bg= und ?fg= unten). Bei layout=eink wird theme=custom ignoriert und auf light zurückgefallen (E-Ink-Kompatibilität).
  • ?bg=<hex>&fg=<hex> — Überschreibt custom_bg_color und custom_fg_color bei theme=custom. Farben müssen als Hex-Werte im Format #RRGGBB angegeben werden.
    • Beispiel: http://localhost:8080/?theme=custom&bg=%23001133&fg=%23ffee00 setzt einen dunkelblauen Hintergrund mit gelber Schrift (URL-kodiert: # als %23).
    • Ungültige Hex-Werte führen dazu, dass theme=custom auf light zurückfällt.
  • ?layout=<layout> — Überschreibt layout aus config.ini. Erlaubte Werte: highres, tablet, eink, custom.
    • Beispiel: http://localhost:8080/?layout=eink wechselt zum E-Ink-Layout.
  • ?width=<pixel>&height=<pixel> — Überschreibt custom_width und custom_height bei layout=custom. Fehlen die URL-Parameter, wird auf die Werte aus config.ini zurückgegriffen.
    • Beispiel: http://localhost:8080/?layout=custom&width=1000&height=700 setzt eine benutzerdefinierte Auflösung.
  • ?title=1|0 (bzw. yes/no, true/false, on/off, case-insensitive) — Überschreibt show_title aus config.ini für den aktuellen Aufruf.
    • Beispiel: http://localhost:8080/?title=0 versteckt den Seitentitel für diesen Aufruf.
  • ?clock=1|0 (dieselben akzeptierten Werte wie ?title=) — Überschreibt show_clock aus config.ini für den aktuellen Aufruf.
    • Beispiel: http://localhost:8080/?clock=0 versteckt die Uhrzeit für diesen Aufruf.

Ungültige oder unbekannte Werte in URL-Parametern werden ignoriert; die App fällt dann auf die config.ini-Werte zurück.

Kombiniertes Beispiel:

http://localhost:8080/?theme=dark&layout=eink&title=0&clock=1

Dies aktiviert Dark Mode, das E-Ink-Layout, versteckt den Titel und zeigt die Uhr für einen Aufruf, unabhängig von den Werten in config.ini.

Beispiel mit benutzerdefinierten Farben:

http://localhost:8080/?theme=custom&bg=%23001133&fg=%23ffee00&layout=tablet

Dies verwendet ein benutzerdefiniertes Farbschema (dunkelblaue Hintergrund, gelbe Schrift) im Tablet-Layout.

Starten

python app.py

Die Anwendung startet auf dem in config.ini konfigurierten Port (Standard: 8080).

Öffne im Browser: http://localhost:8080

Features

  • Nur Straßenbahnen: Busse und andere Verkehrsmittel werden gefiltert.
  • Live-Daten: Direkt von der DVB/VVO API.
  • Auto-Refresh: Seite aktualisiert sich automatisch (konfigurierbar).
  • Fehlertoleranz: Falls eine Haltestelle nicht abrufbar ist, wird die Fehlermeldung angezeigt, die App funktioniert aber weiter.
  • E-Ink-optimiert: Minimalistisches Schwarz-Weiß-Design, große lesbare Schrift.

Dateien

  • app.py — Flask-Hauptanwendung
  • dvb_api.py — DVB/VVO API-Zugriff
  • list_stops.py — Hilfskript zur Haltestellensuche
  • config.ini — Konfigurationsdatei
  • templates/index.html — HTML-Template
  • requirements.txt — Python-Abhängigkeiten

Docker

Diese Anwendung kann auch als Docker-Container ausgeführt werden.

Image bauen

docker build -t haltestellen-info .

Container starten

Starte den Container mit der eigenen config.ini als Volume gemountet, sodass Haltestellen und Einstellungen ohne Neubau des Images geändert werden können:

docker run --rm -d -p 8080:8080 --name haltestellen-info -v "$(pwd)/config.ini:/app/config.ini:ro" haltestellen-info

Hinweis: Wird der Port in config.ini geändert (z.B. port = 9090), muss das Docker-Port-Mapping entsprechend angepasst werden:

docker run --rm -d -p 9090:9090 --name haltestellen-info -v "$(pwd)/config.ini:/app/config.ini:ro" haltestellen-info

Im Browser kann die Anwendung dann unter http://localhost:8080 (oder dem gewählten Port) aufgerufen werden.

Docker Compose

Alternativ kann die Anwendung mit Docker Compose gestartet werden, was Build und Start in einem Schritt kombiniert und automatisch die config.ini als Volume mountet.

Starten (Image wird automatisch gebaut, läuft im Hintergrund):

docker compose up -d --build

Logs ansehen:

docker compose logs -f

Stoppen:

docker compose down

Hinweis: Wird der Port in config.ini geändert (z.B. port = 9090), muss das Port-Mapping in docker-compose.yml entsprechend angepasst werden ("9090:9090" statt "8080:8080").

Richtungsfilter nutzen

Das Hilfsskript list_stops.py hat einen speziellen Modus, um die verfügbaren Richtungen für eine Haltestelle anzuzeigen:

python list_stops.py --richtungen <exakter Haltestellenname>

Beispiel:

python list_stops.py --richtungen Postplatz

Die Ausgabe zeigt eine Tabelle mit allen aktuell verfügbaren Linien und deren Richtungen an dieser Haltestelle. Du kannst diese Informationen dann im [richtungen]-Abschnitt von config.ini eintragen.

list_stops.py im Container

Das Hilfsskript list_stops.py zur Haltestellensuche ist im Docker-Image enthalten und kann per docker exec im laufenden Container ausgeführt werden:

Mit Docker Compose (Service heißt app):

docker compose exec app python3 list_stops.py <Suchbegriff>

Mit manuellem docker run (Container muss mit --name gestartet worden sein):

docker exec haltestellen-info python3 list_stops.py <Suchbegriff>

Beispiel:

docker exec haltestellen-info python3 list_stops.py Postplatz

Der gefundene exakte Haltestellenname kann dann in die lokale config.ini (auf dem Host) eingetragen werden. Diese ist read-only in den Container gemountet; Änderungen wirken sich sofort beim nächsten Laden der Webseite im Browser aus — ein Neustart des Containers ist nicht nötig.

Logging

Bei jedem Aufruf der Startseite werden auf der Server-Konsole folgende Informationen geloggt:

  • Client-IP — IP-Adresse des Clients
  • User-Agent — Identifizierung des Browsers/Clients
  • Layout und Auflösung — Das verwendete Layout (highres, tablet, eink, oder custom) und die konfigurierte Auflösung

Beispiel einer Logzeile:

[Aufruf] IP=192.168.1.100 User-Agent=Mozilla/5.0... Layout=eink (800x480)

Zusätzlich meldet ein kleines, optionales JavaScript-Snippet die tatsächliche Browser-Fenstergröße an einen separaten Endpunkt /log-resolution (progressive enhancement — die Seite funktioniert auch ohne JavaScript). Diese Informationen landen ebenfalls in den Logs:

[Client-Auflösung] IP=192.168.1.100 Fenstergröße=1024x768

Die Logs können je nach Betriebsumgebung angezeigt werden:

  • Lokale Ausführung: direkt auf der Konsole (wo app.py gestartet wurde)
  • Docker: über docker compose logs -f (bei Compose) oder docker logs <container-name> (bei manuellen Containern)

Lizenz

Frei verwendbar.