diff --git a/AGENTS.md b/AGENTS.md index 367fab9..79ce5ae 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -91,14 +91,16 @@ Root files: `dashboard-muster*.html` = original static prototype (superseded, re `bauauftrag.md`/`.html` = original build brief (historical), `DESIGN_BRIEF_DATAMETRIC360.md` = the prompt for the Claude Design project. -**`homeassistant/` in one paragraph:** 10 pyscript scripts + 4 modules (`pyscript/modules/`); trip -detection via the iPhone WLAN sensor with pause tolerance, two-stage trip completion via HA history -screening (odometer often updates only on the next trip), fill-up detection on fuel-level rise, -Shell PDF parser (`data/shell_beleg_parser.py`, subprocess, the only tested part of the repo), tire -km counter, backup, self-update, image management. Frontend: one file `www/audi-dashboard-app.js` -(3,130 lines, custom element, no framework/bundler), 5 tabs + ~19 detail routes, cache-busting via -`audi-dashboard-version.json` + loader stub. Entity IDs configured centrally in -`pyscript/modules/einstellungen.py` (the one file edited before install). Deploy: `update.ps1` +**`homeassistant/` in one paragraph:** 10 pyscript scripts + 5 modules (`pyscript/modules/`); trip +detection via the FMM003 ignition sensor with pause tolerance (the iPhone WLAN sensor is gone — see +section B), two-stage trip completion via HA history screening (odometer often updates only on the +next trip), fill-up detection on fuel-level rise, Shell PDF parser (`data/shell_beleg_parser.py`, +subprocess, the only tested part of the repo), tire km counter, backup, self-update, image +management. Frontend: one file `www/audi-dashboard-app.js` +(~4,000 lines, custom element, no framework/bundler), 5 tabs + ~19 detail routes, cache-busting via +`audi-dashboard-version.json` + loader stub. Entity IDs are assigned **in the UI** (Settings → +Fahrzeug einrichten → Setup), stored as overrides in `data/entitaeten.json`; +`pyscript/modules/einstellungen.py` holds only the built-in defaults. Deploy: `update.ps1` (robocopy to Samba share) or — still inactive — self-update from git. **`companion-app/` — what exists:** dependency-free, strictly typed TS data layer (`src/api/`): @@ -111,8 +113,10 @@ capacitor/iframe/browser (`umgebung.ts`), types + entity table (`types.ts`), fac **DataMetric360 architecture (short — details in `COMPANION_APP_ARCHITECTURE.md`):** - Future data source: **Teltonika FMM003** on the CAN bus, fully replacing the iPhone WLAN sensor and the VAG integration. -- **Current data path (since 2026-08-11): Codec JSON → MQTT/TLS → Mosquitto add-on → HA.** Traccar - is **dropped** (the decision log deliberately remains in the architecture doc, marked ÜBERHOLT). +- **Current data path (since 2026-08-12): FMM003 → flespi (native Codec8/TCP, IMEI auth) → HA.** + Both earlier directions are dropped: Traccar first, then the self-hosted MQTT/TLS broker — the + router's port-forward turned out to be unusable. The decision logs deliberately remain in the + architecture doc, marked ÜBERHOLT. Details and open steps in section B below. - Frontend access: HA REST + WebSocket with a long-lived access token (no `hass` object). - External access: Cloudflare Tunnel + reverse proxy with a path allowlist; HA itself stays unreachable. Domain **`datametric360.app`** registered (all-inkl, 2026-08-11). @@ -317,9 +321,9 @@ capacitor/iframe/browser (`umgebung.ts`), types + entity table (`types.ts`), fac Parkplatz" state, fuel/range, and Route (Google Maps deep link) / Teilen (Web Share API) actions. Backend: new `STANDORT_TRACKER` entity-ID setting in `einstellungen.py` (device_ tracker with lat/lon attributes), published via a new `_standort()` helper in - `frontend_veroeffentlichung.py` — **left empty/unconfigured**, no live vehicle GPS source - exists yet (same FMM003/flespi gap as section B); the tile shows "Kein GPS-Signal vom - Fahrzeug" until that's wired up. Verified end-to-end in `audi_ha_test` with a manually + `frontend_veroeffentlichung.py`. The built-in default points at the author's test device + (`device_tracker.testzone_fmm003`); until the FMM003 actually delivers positions (section B), + that entity does not exist and the tile shows "Kein GPS-Signal vom Fahrzeug". Verified end-to-end in `audi_ha_test` with a manually created `device_tracker.test_fahrzeug` test entity (tile, fullscreen map, and menu all confirmed rendering/populating correctly); the device's own location (browser Geolocation API) and the Route/Teilen deep links work independently of the vehicle-GPS gap. Pushed to diff --git a/SPECIFICATION.md b/SPECIFICATION.md index 9f3f233..020d932 100644 --- a/SPECIFICATION.md +++ b/SPECIFICATION.md @@ -1,5 +1,21 @@ # Audi Dashboard — Technical Specification +> ## ⚠️ Teilweise überholt (Stand 2026-08-13) +> +> Dieses Dokument beschreibt den Stand **vor** der FMM003-Umstellung. Drei Dinge haben sich seither +> geändert und gelten in diesem Dokument durchgehend als veraltet: +> +> 1. **Fahrterkennung** läuft über den Zündungssensor des FMM003, nicht mehr über den +> iPhone-WLAN-Sensor. `sensor.iphone_wifi_connection` und `fahrzeug.wlan_name` sind entfernt. +> 2. **Datenquelle** ist der FMM003 über flespi (Codec8/TCP), nicht mehr die HACS-Integration +> `TommiG1/HA_VAG-EU-Data-Act`. +> 3. **Entity-IDs** werden im Setup-Menü der App zugeordnet (Einstellungen → Fahrzeug einrichten → +> Setup) und in `data/entitaeten.json` abgelegt. `einstellungen.py` enthält nur noch die +> eingebauten Vorgabewerte und ist keine Pflicht-Bearbeitung mehr vor der Installation. +> +> Alles Übrige — Datenmodell, Geschäftsregeln, Frontend-Aufbau, §7 „Known Gaps" — gilt weiterhin. +> Den aktuellen Stand führt `AGENTS.md`, Abschnitt B. + **Audience:** an AI coding agent picking up this codebase with no prior context. **Scope:** the Home Assistant panel (`homeassistant/`) — the finished, in-use app. A separate sibling project, `design-system/`, is a standalone React component-library replica of this app's visual language, built solely to feed Claude Design (`claude.ai/design`) via the `/design-sync` skill; it is **not** part of this app and deliberately excludes Audi brand assets. `COMPANION_APP_ARCHITECTURE.md` documents a third, **not-yet-built** sibling project — an iOS/Android/HA-iframe companion app fed by a Teltonika FMM003 tracker instead of the WLAN-sensor/VAG-integration data sources described below; its design is decided but no code exists yet. Don't confuse any of the three. diff --git a/design/README.md b/design/README.md index 375946c..527e237 100644 --- a/design/README.md +++ b/design/README.md @@ -14,9 +14,9 @@ Das ist der **Entwurf**, nicht der lauffähige Code. Umgesetzt wird er später i | `DataMetric360.dc.html` | Einstiegsdatei des Entwurfs | | `DM360.dc.html` | Die eigentlichen Bildschirme und Zustände | | `DataMetric360 Board.dc.html` | Vergleichsansicht: dieselbe App gleichzeitig als Smartphone- und Großbildschirm-Rahmen nebeneinander, mit Bildschirm-/Theme-Umschalter. Steuert beide Rahmen per `postMessage`. | -| `dm360-host.html` | Lädt `audi-dashboard-app.js` in einem eigenen ``, hängt danach `audi-dashboard-ios.css` in dessen Shadow-Root - der eigentliche Träger hinter dem Board. | +| `dm360-host.html` | Lädt `audi-dashboard-app.js` in einem eigenen ``, hängt danach `audi-dashboard-ios.css` in dessen Shadow-Root - der eigentliche Träger hinter dem Board. **Achtung: beide Dateien liegen nicht in diesem Ordner.** Aus der Repo-Kopie heraus bleibt das Board deshalb leer; es läuft nur im Claude-Design-Projekt, wo sie mit hochgeladen sind. | | `ios-frame.jsx` | iOS-26-Gerätekachel (Statusleiste, Dynamic Island, Home-Indikator) - reine Optik, keine App-Logik. | -| `audi-dashboard-ios.css` | **Die eigentliche Neuerung dieses Exports.** Optik-Auflage über `audi-dashboard.css`: iOS-natives Erscheinungsbild (44-px-Zeilen, transluzente Tab-Leiste, iOS-Schalter) plus - wichtig - die responsive Großbildschirm-Umsetzung per `@container (min-width:860px)` (Tab-Leiste wird zur seitlichen Navigation). **Seit 2026-08-11 in `homeassistant/www/` scharf geschaltet und im Docker-Testcontainer bei 375px und 1280px verifiziert** - rührt `audi-dashboard-app.js` nicht an, wie behauptet. | +| `audi-dashboard-ios.css` *(liegt in `../homeassistant/www/`, nicht in diesem Ordner)* | **Die eigentliche Neuerung dieses Exports.** Optik-Auflage über `audi-dashboard.css`: iOS-natives Erscheinungsbild (44-px-Zeilen, transluzente Tab-Leiste, iOS-Schalter) plus - wichtig - die responsive Großbildschirm-Umsetzung per `@container (min-width:860px)` (Tab-Leiste wird zur seitlichen Navigation). **Seit 2026-08-11 in `homeassistant/www/` scharf geschaltet und im Docker-Testcontainer bei 375px und 1280px verifiziert.** Die Auflage selbst ist rein additiv; `audi-dashboard-app.js` wurde nur um den Stylesheet-Loader ergänzt, der sie nachlädt (siehe unten). | | `datametric360-ios.css` | Dieselbe Optik-Auflage, aber für die `@audi-dash/ui`-Komponentenklassen (`.ads-*`) statt für die Panel-eigenen Klassen - für später, wenn `companion-app/` eine UI bekommt. | | `support.js` | Hilfsfunktionen des Entwurfs | | `assets/` | Icons, Logos, Typenschilder und Schriften, die der Entwurf verwendet | diff --git a/homeassistant/INSTALL.md b/homeassistant/INSTALL.md index 03c6803..9a89efa 100644 --- a/homeassistant/INSTALL.md +++ b/homeassistant/INSTALL.md @@ -93,8 +93,13 @@ Anders als früher wird dafür **nicht** mehr `pyscript/modules/ einstellungen.py` von Hand bearbeitet — das übernimmt ein grafisches Setup-Menü direkt in der App: **Mein Audi → Einstellungen → Fahrzeug einrichten → Einrichten → „Setup — Sensoren zuordnen"** (letzter Punkt, -erscheint erst nach Klick auf „Einrichten"). Dafür muss die App bereits -laufen, siehe Schritt 9 zuerst. +erscheint erst nach Klick auf „Einrichten"). + +> **Reihenfolge beachten:** Dieser Schritt braucht eine bereits laufende App. +> Arbeite deshalb erst die Schritte 5 bis 9 ab (Token, Neustart, Prüfung, +> Restarbeiten, Frontend) und komm dann hierher zurück. Schritt 7 verweist +> seinerseits auf die hier vorgenommene Zuordnung — das ist kein Widerspruch, +> sondern schlicht die Reihenfolge: erst starten, dann zuordnen, dann prüfen. Das Setup-Menü listet jede Sensor-Rolle, die die App kennt (Zündung/ Fahrterkennung, Kilometerstand, Tankfüllstand, Standort, Batteriespannung, @@ -104,6 +109,16 @@ anzeigen" grenzt auf die erwartete Domäne/Einheit ein) und schreibt die Auswahl direkt in eine Override-Datei — `einstellungen.py` selbst bleibt unverändert. +Die Override-Datei ist `/config/audi_dashboard/entitaeten.json`. Sie wird von +der automatischen Sicherung und vom Backup-Export mit erfasst; ein +Wiederherstellen spielt die Zuordnung also mit zurück. + +**Hinweis zu den Vorgabewerten:** Drei Rollen sind in `einstellungen.py` mit +den Test-Entitäten der Entwicklungsinstanz vorbelegt (Zündung, Batterie- +spannung, Standort — jeweils `*_testzone_fmm003`). Auf einer frischen +Installation zeigen sie ins Leere; das Setup-Menü meldet dann „Entität nicht +gefunden". Einfach die eigenen Entitäten zuordnen, damit ist es erledigt. + **Zwingend, damit die Fahrterkennung läuft:** - **Zündung/ACC-Status** (`ZUENDUNG_SENSOR`) — ein `binary_sensor`, `on` = Fahrt läuft. Kommt vom Teltonika FMM003 (z. B. @@ -226,8 +241,9 @@ Der `panel_custom`-Eintrag aus Schritt 3 zeigt auf Prototyp. Das Gerät braucht dafür zusätzlich zur Tailscale-Verbindung normalen Internetzugang — sonst bleibt die Karte auf der Fahrt- und Tankvorgang-Detailseite leer. -- **Statistik-Seite** zeigt weiterhin Beispielzahlen aus dem Prototyp, - keine echte Auswertung der eigenen Fahrten — eigenes Arbeitspaket. +- **Statistik-Seite** wertet die eigenen Fahrten und Tankvorgänge echt aus + (Zeiträume, Verbrauch, Tag/Nacht, privat/Arbeitsweg). Sie bleibt nur so + lange leer, wie noch keine Fahrten und Tankungen erfasst sind. ## Schritt 10 — künftige Updates einspielen, ohne die App neu zu bauen diff --git a/homeassistant/README.md b/homeassistant/README.md index 04c3a86..f5ae4bc 100644 --- a/homeassistant/README.md +++ b/homeassistant/README.md @@ -96,22 +96,26 @@ Datendateien — nie App-Code oder -Konfiguration. `fahrterkennung.py`. - **Bilder fehlen** (§7a) — Ordner `www/bilder/` ist noch leer. Layout springt nicht (Maße sind reserviert), aber die Flächen bleiben leer. -- **Statistik-Seite** zeigt weiterhin Beispielzahlen aus dem Prototyp, keine - echte Auswertung der erfassten Fahrten. - **Leaflet lädt per CDN**, wie im Prototyp — braucht zusätzlich zu Tailscale echten Internetzugang auf dem Gerät. ## Was schon funktioniert (getestet) -- Fahrterkennung über WLAN mit Pausenregel (`task.unique` + `task.sleep`) +- Fahrterkennung über den Zündungssensor mit Pausenregel (`task.unique` + `task.sleep`); + bis 2026-08-12 lief sie über den WLAN-Sensor des iPhones - Zweistufiger Fahrtabschluss per Recorder-Historie-Screening, inklusive Verkettung direkt anschließender Fahrten - Reifenzähler per direkter Subtraktion, kein `utility_meter` -- Belegverarbeitung inklusive 97-%-Volltankungsregel und Duplikatserkennung - über `receipt_key` +- Belegverarbeitung mit Duplikatserkennung über `receipt_key` (die zunächst + geplante 97-%-Volltankungsregel wurde per Änderungswunsch entfernt, siehe + Kopfkommentar in `pyscript/belegverarbeitung.py`) - Manuelle Fallback-Wege für Fahrten und Tankvorgänge ohne Beleg - Frontend: Übersicht, Fahrtenliste, Navigation zwischen allen Ansichten, Datenadapter Profil→Oberfläche, Schreibaktionen über `hass.callService` +- Statistik-Seite mit echter Auswertung aus Fahrten und Tankvorgängen + (Zeiträume, Verbrauch, Tag/Nacht, privat/Arbeitsweg) +- Setup-Menü für die Sensor-Zuordnung, inklusive Sicherung in + `data/entitaeten.json` ## Dateiübersicht @@ -129,12 +133,18 @@ homeassistant/ │ ├── modules/ │ │ ├── einstellungen.py zentrale Entity-ID-Konfiguration (Schritt 4) │ │ ├── profil.py Datenzugriff (§6) +│ │ ├── entitaeten.py Sensor-Zuordnung aus dem Setup-Menü │ │ ├── fahrtabschluss_logik.py Screening-Logik (§7.2) │ │ └── frontend_veroeffentlichung.py Zustände fürs Frontend (§10 Punkt 7 Ersatz) -│ ├── fahrterkennung.py §7.1 +│ ├── fahrterkennung.py §7.1 (Zündungssensor, früher WLAN) │ ├── fahrtabschluss.py §7.2 (Trigger-Registrierung) +│ ├── tankerkennung.py §7.4 (automatische Erkennung am Füllstandsanstieg) │ ├── reifenzaehler.py §7.5 │ ├── belegverarbeitung.py §7.4, §7.7 +│ ├── batterieverlauf.py 12-V-Spannung, Tagesminimum/-maximum +│ ├── bilderverwaltung.py Upload/Löschen der Fahrzeugfotos +│ ├── backup.py tägliche Sicherung und Wiederherstellung +│ ├── updateverwaltung.py Update suchen und installieren │ └── frontend_api.py Lese-/Schreib-Anbindung fürs Frontend ├── www/ │ ├── audi-dashboard-panel.js Lade-Stub (zeigt configuration.yaml hierher), ändert sich kaum diff --git a/homeassistant/data/fahrzeugprofil.example.json b/homeassistant/data/fahrzeugprofil.example.json index 901e04d..d8ea904 100644 --- a/homeassistant/data/fahrzeugprofil.example.json +++ b/homeassistant/data/fahrzeugprofil.example.json @@ -1,5 +1,5 @@ { - "_hinweis": "Vorlage ohne echte Fahrzeug-/Personendaten. Vor der Installation nach fahrzeugprofil.json kopieren und die Platzhalter unten ersetzen (VIN, Kennzeichen, Erstzulassung, HU-Termin, WLAN-Name, Versicherung, Werkstatt, Servicebuch) - am einfachsten über den Button 'Einrichten' in den Einstellungen der App, sobald sie einmal läuft. Diese Datei selbst bleibt bewusst im Repo (siehe .gitignore), die echte fahrzeugprofil.json nicht.", + "_hinweis": "Vorlage ohne echte Fahrzeug-/Personendaten. Vor der Installation nach fahrzeugprofil.json kopieren und die Platzhalter unten ersetzen (VIN, Kennzeichen, Erstzulassung, HU-Termin, Versicherung, Werkstatt, Servicebuch) - am einfachsten über den Button 'Einrichten' in den Einstellungen der App, sobald sie einmal läuft. Diese Datei selbst bleibt bewusst im Repo (siehe .gitignore), die echte fahrzeugprofil.json nicht.", "fahrzeug": { "fin": "", diff --git a/homeassistant/update.ps1 b/homeassistant/update.ps1 index 46bf46e..d50518e 100644 --- a/homeassistant/update.ps1 +++ b/homeassistant/update.ps1 @@ -21,10 +21,16 @@ ohne Cache und lädt den eigentlichen Code darüber immer frisch nach (siehe Kopfkommentar in www/audi-dashboard-panel.js). - Absichtlich NICHT kopiert: data/ - das würde ein bereits laufendes - Fahrzeugprofil, die Fahrten- und Tankvorgänge-Archive überschreiben. Die - data/-Dateien sind nur die Erstbefüllung für die einmalige Installation - (siehe INSTALL.md Schritt 2). + Absichtlich NICHT kopiert: die Datenbestände in data/ - das würde ein + bereits laufendes Fahrzeugprofil, die Fahrten- und Tankvorgänge-Archive + sowie die Sensor-Zuordnung überschreiben. Diese Dateien sind nur die + Erstbefüllung für die einmalige Installation (siehe INSTALL.md Schritt 2). + + Eine Ausnahme davon ist shell_beleg_parser.py: die Datei liegt zwar in + data/, ist aber Code, kein Datenbestand - belegverarbeitung.py ruft sie + als Unterprozess aus /config/audi_dashboard/ auf. Ohne diese Ausnahme + käme jede Änderung am Belegleser (dem einzigen getesteten Teil des + Projekts) auf keiner Instanz an. .PARAMETER Ziel Pfad zum config-Verzeichnis von Home Assistant, z. B. ein per Samba @@ -55,6 +61,13 @@ Copy-Item "$hier\www\audi-dashboard-panel.js" "$Ziel\www\audi-dashboard-panel.js Copy-Item "$hier\www\audi-dashboard.css" "$Ziel\www\audi-dashboard.css" -Force Copy-Item "$hier\www\audi-dashboard-ios.css" "$Ziel\www\audi-dashboard-ios.css" -Force +# Code, der in data/ liegt (siehe Kopfkommentar) - der Ordner selbst wird +# bewusst nicht gespiegelt, diese eine Datei aber schon. +if (Test-Path "$Ziel\audi_dashboard") { + Copy-Item "$hier\data\shell_beleg_parser.py" "$Ziel\audi_dashboard\shell_beleg_parser.py" -Force + Write-Host " Belegleser aktualisiert" +} + if (Test-Path "$hier\www\bilder") { Write-Host "Kopiere www/bilder/ ..." -ForegroundColor Cyan New-Item -ItemType Directory -Force -Path "$Ziel\www\bilder" | Out-Null diff --git a/homeassistant/www/audi-dashboard-app.js b/homeassistant/www/audi-dashboard-app.js index 8b0b98e..c8debcf 100644 --- a/homeassistant/www/audi-dashboard-app.js +++ b/homeassistant/www/audi-dashboard-app.js @@ -500,13 +500,6 @@ const STANDORT_PEEK_PX = 96; // sichtbarer Anteil im geschlossenen Zustand, muss function standortBekannt() { return CAR.standortLat != null && CAR.standortLon != null; } -/* Fahrzeug-Symbol im myAudi-Stil: einfaches Top-down-Glyph, noch fuer - Vorschauen in Gebrauch; die Kartenmarkierung nutzt poi-car (Audi CI). */ -function fahrzeugGlyphPfade() { - return ` - - `; -} /* Kartenmarkierung: poi-car aus dem Audi-CI-Satz (assets/icons/poi-car.svg). Die Spitze sitzt unten, deshalb ankert Leaflet am unteren Rand. */ function fahrzeugMarkerSVG(px = 34) { @@ -514,12 +507,14 @@ function fahrzeugMarkerSVG(px = 34) { } /* Fahrzustand fürs Menü: "fährt" solange die aktuelle Fahrt noch offen ist - (siehe fahrterkennung.py), sonst "steht" - erst ab der in "Fahrten - zusammenfassen" hinterlegten Pausenzeit (CONFIG.pauseMin) gilt der - Stillstand als endgültig genug für "Letzter Parkplatz" statt eines - bloßen Zwischenstopps. Ohne echtes Bewegungssignal vom Fahrzeug (siehe - AGENTS.md, FMM003/flespi offen) ist das die beste Näherung aus den - bereits vorhandenen Fahrtdaten. */ + (siehe fahrterkennung.py), sonst "steht". Ohne echtes Bewegungssignal vom + Fahrzeug (siehe AGENTS.md, FMM003/flespi offen) ist das die beste Näherung + aus den bereits vorhandenen Fahrtdaten. + + parkplatz unterscheidet einen endgültigen Stillstand (laenger als die in + "Fahrten zusammenfassen" hinterlegte Pausenzeit) von einem blossen + Zwischenstopp. Das Feld ist vorbereitet, wird aber derzeit von keiner + Ansicht gelesen - eine "Letzter Parkplatz"-Anzeige gibt es noch nicht. */ function standortZustand() { const t = TRIPS[0]; if (t && t.status === "offen") return { faehrt: true, seitTs: null, parkplatz: false }; @@ -812,7 +807,8 @@ function vStandort() {
-
-
+ + @@ -3095,6 +3096,12 @@ function ereignisseVerdrahten() { ROOT.getElementById("theme").addEventListener("click", () => { themeSetzen(HOST.dataset.theme === "nacht" ? "tag" : "nacht"); themeIcon(); + /* Neu zeichnen, damit auch die Leaflet-Kacheln den Stil wechseln: die + Kachel-URL wird beim Aufbau aus TILES[theme] gewaehlt und nicht + nachtraeglich aktualisiert. Ohne dies blieb die Karte bis zum naechsten + Backend-Update im alten Stil - seit der Dauerkarte auf der Uebersicht + deutlich sichtbar. */ + render(); }); // Wischgeste über Pointer Events (nicht Touch Events), damit dieselbe // Logik auch mit der Maus funktioniert (z. B. beim Testen im Browser). @@ -3316,6 +3323,14 @@ function ereignisseVerdrahten() { // Klick irgendwo sonst im Popup (aber nicht auf den Catcher, der schon // oben behandelt wurde) schließt ein offenes Dropdown, ohne das ganze // Popup zu verlassen. + /* Den Filterschalter VOR dem Schliessen der Auswahlliste behandeln. + Sonst ersetzt render() unten das Overlay-DOM, bevor das + change-Ereignis des Kontrollkaestchens ausgeliefert wird - der + Schalter sprang dann beim naechsten Zeichnen einfach zurueck. */ + if (e.target.closest("[data-setup-nurpassend]") || e.target.closest(".switch")) { + const kasten = ROOT.querySelector("[data-setup-nurpassend]"); + if (kasten) { setupNurPassend = !setupNurPassend; render(); return; } + } if (setupSucheOffen && !e.target.closest(".entitaet-combo")) { setupSucheOffen = null; setupSuchtext = ""; render(); return; } return; } @@ -3590,6 +3605,7 @@ function ereignisseVerdrahten() { if (art) { const tr = TRIPS.find((x) => x.trip_id === art.dataset.art); tr.art = tr.art === "arbeitsweg" ? "privat" : "arbeitsweg"; render(); return; } // Standort (Vollbild) - Karten-/Menü-Bedienung manipuliert SMAP/das Menü- // DOM direkt statt über render() (siehe Kopfkommentar Standort-Abschnitt). + if (e.target.closest("[data-standort-umschalten]")) { standortMenuUmschalten(); return; } if (e.target.closest("[data-standort-layer]")) { SMAP_STIL = SMAP_STIL === "satellit" ? "strasse" : "satellit"; standortTiles(); return; } if (e.target.closest("[data-standort-fahrzeug]")) { standortAufFahrzeug(); return; } if (e.target.closest("[data-standort-user]")) { standortAufUser(); return; } diff --git a/homeassistant/www/audi-dashboard.css b/homeassistant/www/audi-dashboard.css index b3eadb5..7559434 100644 --- a/homeassistant/www/audi-dashboard.css +++ b/homeassistant/www/audi-dashboard.css @@ -749,7 +749,19 @@ button.tile, .tilebtn { transition: background .15s, transform .1s; } } .standortmenu.offen { transform: translateY(0); } .standortmenu-griffzone { padding: 10px 0 14px; touch-action: none; cursor: grab; position: relative; } -.standortmenu-griff { width: 36px; height: 4px; border-radius: 2px; background: var(--line-strong); margin: 0 auto; } +/* Der Griff ist jetzt ein Knopf (Tastaturzugang zum Menue). Die Knopf- + Voreinstellungen des Browsers werden deshalb zurueckgesetzt; die + Trefferflaeche waechst per Pseudo-Element auf 44px, ohne den sichtbaren + Strich zu vergroessern. */ +.standortmenu-griff { + position: relative; display: block; width: 36px; height: 4px; + border: 0; padding: 0; border-radius: 2px; + background: var(--line-strong); margin: 0 auto; cursor: pointer; +} +.standortmenu-griff::after { + content: ""; position: absolute; left: 50%; top: 50%; + transform: translate(-50%, -50%); width: 88px; height: 44px; +} .standortmenu-schliessen { position: absolute; top: 14px; right: 0; width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; @@ -762,7 +774,6 @@ button.tile, .tilebtn { transition: background .15s, transform .1s; } .standortmenu-adresse { font-size: 13.5px; color: var(--fg2); margin-top: 20px; } .standortmenu-status { display: flex; align-items: center; gap: 9px; margin-top: 8px; font-size: 13.5px; color: var(--fg2); } .standortmenu-status svg { color: var(--fg3); flex: 0 0 auto; } -.dot.neutral { background: var(--fg3); } .standortmenu-werte { display: flex; align-items: center; gap: 10px; margin-top: 8px; font-size: 13.5px; color: var(--fg2); } .standortmenu-werte svg { color: var(--fg3); flex: 0 0 auto; } .standortmenu-aktionen { display: flex; gap: 10px; margin-top: 18px; padding-bottom: 4px; }