Batteriespannungs-Messwertliste, Wisch-Löschen, Reifensatz-Archiv, CI-Icons
Fünf vom Nutzer angeforderte Erweiterungen in einer Runde:
- Batteriespannungs-Kachel bekommt eine Messwertliste (Datum, Uhrzeit,
Spannung, optional Außentemperatur über den neuen AUSSENTEMP_SENSOR),
erreichbar über ein neues list-s-Symbol in der Diagramm-Kachel. Werte
über AGM_RUHE_MAX_V (12,8 V) sind keine Ruhespannung, sondern
Lichtmaschinenspannung - die Zeile markiert das jetzt mit
"Generatorspannung" statt es unkommentiert als Messwert auszugeben.
- Jede Zeile der neuen Liste wischbar zum Löschen (neuer Dienst
batterieverlauf_loeschen), über dieselbe Wisch-Mechanik wie Fahrten/
Tankvorgänge in beiden Oberflächen.
- Batteriespannungs-Diagramm im Panel war auf großen Bildschirmen (≥860px,
Spaltenlayout) stark in die Breite gezogen (preserveAspectRatio="none"
bei fester Höhe) - gedeckelt wie die dort bereits vorhandenen Popups.
- Statistik-Tab-Symbol in beiden Oberflächen durch das Audi-CI-Symbol
polls-s ersetzt.
- Neue Möglichkeit, einen Reifensatz zu archivieren ("Neue Räder
anlegen"): der aktuelle Stand (km, Marke, Modell, DOT, Maße, Solldruck,
Kommentar) wandert in ein Archiv, der laufende Satz beginnt bei 0 km neu.
Archiv als aufklappbare Übersicht mit voller Bearbeitungsmöglichkeit,
über drei neue, bewusst nicht über profilSchreiben laufende Dienste
(reifen_archivieren/-aktualisieren/-loeschen) - aus demselben Grund wie
reifen_wechseln: kein im Browser gehaltener Stand darf einen
zwischenzeitlich fortgeschriebenen km-Wert überschreiben.
Live im Testcontainer geprüft (erstmals über :18123 statt :8123 erreichbar)
und dabei zwei echte Layout-Fehler gefunden, die kein Compile-/Testlauf
sehen konnte: die Archiv-Eingabefelder waren durch ein fälschlich
verwendetes .mitEinheit (feste 96px-Breite, eigentlich für Zahl+Einheit
gedacht) abgeschnitten ("Continenta" statt "Continental"), und die
Kilometerzahl in der eingeklappten Archiv-Zeile war klein an das Datum
gequetscht statt wie der Satzname lesbar. Beides behoben, live erneut
bestätigt.
Backend: py_compile clean, services.yaml ergänzt. Panel: node --check
clean. companion-app: tsc/Testsuite (146/146)/Build/OTA-Bündel alle grün.
Manifest 2026.8.25.2 → .8, jeder Neustart im Testcontainer sauber.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2942,6 +2942,150 @@ confirmed mechanism the pending Sicherheit plan already documented. `screening.p
|
||||
`TankDetail.tsx` were deliberately left untouched: the estimate flows through existing display/edit paths
|
||||
without needing either to change.
|
||||
|
||||
## R. Five owner-requested features in one round: battery measurement list, swipe-delete, diagram-width fix,
|
||||
CI icon substitutions, wheel-set archiving (2026.8.25.3/.4)
|
||||
|
||||
**1. Battery measurement list.** The battery-voltage tile only ever showed a hand-drawn chart. Added a
|
||||
"list" corner button (CI `list-s`) that opens a new list view — one row per day (the existing daily
|
||||
min/max data, unchanged storage shape) showing date, time, voltage, and now also outside air temperature.
|
||||
Backend: new optional `AUSSENTEMP_SENSOR` role (`einstellungen.py`); `batterie.py`'s 5-minute check now also
|
||||
reads it and passes it to `ablage.batterieverlauf_tageswert_aktualisieren()`, which gained an `aussentemp`
|
||||
parameter — stored as `min_temp_c`, **only updated when a measurement also sets that day's minimum voltage**
|
||||
(the temperature is tied to that specific reading, not a daily average). Older entries and setups without
|
||||
the sensor simply carry `min_temp_c: None` — no backfill, no migration. New screens: companion-app
|
||||
`BatterieListe.tsx` (route `battliste`, reached from an `IconButton`/`SymbolListe` in `Batterie.tsx`'s
|
||||
header) and panel `vBatterieliste()` (route `battliste`, reached via a new `.iconbtn`/`ciSVG(CI.listS)`
|
||||
button in `vBatterieverlauf()`'s tile header).
|
||||
|
||||
**2. Swipe-to-delete for the new list, per entry.** Reused the existing pattern in both codebases rather
|
||||
than inventing a new one: companion-app's `Zeilenmenue` (wipe + accessible menu button, see its own
|
||||
docstring) and the panel's `swipeZeile()`/`eintragLoeschen()`/`LOESCH_TEXT`/`LOESCH_HINWEIS` machinery
|
||||
already used for trips/tank vorgaenge, extended with a `"batt"` art. New backend service
|
||||
`batterieverlauf_loeschen` (field: `datum`) → `ablage.batterieverlauf_eintrag_loeschen()` (new) →
|
||||
`batterie.eintrag_loeschen()` (new, wired in `dienste.py`).
|
||||
|
||||
**3. Battery diagram "still stretched" on a large monitor — panel only (confirmed with the owner; the
|
||||
diagram in question doesn't exist as a separate wide layout in companion-app).** Root cause found in
|
||||
`audi-dashboard-ios.css`: past 860px viewport width the whole app switches to a wide two-column layout
|
||||
(`@container (min-width:860px)`) where `main#view`'s content column is 772px wide (860 − 2×44px side
|
||||
padding). The battery chart's SVG (`#bvSvg`, `audi-dashboard-app.js`) is drawn on a fixed `viewBox="0 0 320
|
||||
170"` with `preserveAspectRatio="none"` and `width:100%` — at 772px wide against a native 320-unit design,
|
||||
that's a ~2.4× horizontal stretch with the height staying fixed at 170px, turning the chart into an
|
||||
unnaturally wide, flat band. Fixed the same way the existing popups in that file already solve the identical
|
||||
problem one section up: `#bvChart{max-width:400px;margin-left:auto;margin-right:auto}` inside the same
|
||||
`@container` block, no changes to the SVG's own drawing logic (`BV_W`/`BV_H`/`bvZeichnen()`), which section
|
||||
O of this file already spent real effort getting right for a *different* stretch bug (the Y-axis
|
||||
rescaling one) — deliberately left untouched here.
|
||||
|
||||
**4. CI icon substitutions — `list-l/-s`, `polls-l/-s`, `package-l/-s`, all requested by the owner
|
||||
(SVG source supplied directly from their local Audi icon export folder, same as every other CI icon in this
|
||||
codebase — see the recurring "vom Nutzer als SVG geliefert, verbatim uebernommen" comment convention).**
|
||||
Added to the `CI` catalog in `audi-dashboard-app.js`. `polls-s` replaces the Statistik tab's hand-drawn bar
|
||||
icon (`ICONS.stat`) in the panel's tab bar — needed adding `"stat"` to `ICONS_VOLL` (the existing mechanism
|
||||
for filled-vs-outline icon rendering; CI paths carry their own `fill="currentColor"` but would otherwise
|
||||
also inherit the tab bar's `stroke:currentColor` from `.tab svg`, doubling the line weight around the
|
||||
shape). Companion-app's `symbole.tsx` had no filled-icon mechanism at all yet (its `SymbolAudi` etc. are
|
||||
plain stroked outlines, unlike the panel's CI-icon-based tab bar) — added a `voll` prop to the shared
|
||||
`Rahmen` wrapper (`fill`/`stroke` swap) as the equivalent mechanism, then `SymbolStatistik` (parity with
|
||||
the panel), plus `SymbolListe`/`SymbolPaket` for the other two icon uses below. `list-s`/`package-s` are the
|
||||
corner/inline buttons described in points 1 and 5; the `-l` (48-grid) variants are stored for parity with
|
||||
every other CI icon pair in the catalog but aren't wired to a render path yet, same as the pre-existing
|
||||
`editL`/`oilChangeL`/etc.
|
||||
|
||||
**5. Wheel-set archiving ("Neue Räder anlegen").** A `package-s` button sits between the wheel photo and
|
||||
the editable Hersteller/Modell fields on the Reifen page in both codebases (panel: inline always-editable
|
||||
`data-rf` inputs, matching that page's existing convention; companion-app: read-only `Wertzeile`s with a
|
||||
separate edit form, matching *its* existing convention — no new interaction pattern introduced in either).
|
||||
Pressing it asks "Neue Räder anlegen?" (panel: the existing `bestaetigen()` action sheet; companion-app: the
|
||||
existing `window.confirm`-based `bestaetigen()` already used by `wechseln()` on the same page) before doing
|
||||
anything. On confirmation, `reifen.py`'s new `archivieren(k, satz)`: snapshots the season's *entire* current
|
||||
record (km, marke, modell, dot, mass, druck_vorne/hinten, kommentar, plus a generated id and today's date as
|
||||
`ersetzt_am`) into `reifen.archiv` (newest first), then resets the live record — **km to 0 (explicit owner
|
||||
decision) and marke/modell/dot/kommentar to blank** (a replacement tire hasn't been characterized yet),
|
||||
**but mass/druck_vorne/druck_hinten/bild carried over** (size and target pressure don't usually change for
|
||||
a same-fitment replacement — a judgment call, not something the owner specified; flag if wrong). Three new
|
||||
services (`reifen_archivieren`, `reifen_archiv_aktualisieren`, `reifen_archiv_loeschen`), all deliberately
|
||||
**bypassing `profilSchreiben`/`profilSpeichern`** for the same reason `reifen_wechseln`/`reifen_km_setzen`
|
||||
already do (see `reifenzaehler.py`'s own docstring) — a full-profile round trip from a stale browser copy
|
||||
could clobber a km value the backend fortgeschrieben in the meantime.
|
||||
|
||||
Overview UI: an "Archiv" tile at the bottom of the Reifen page, one row per archived set. Companion-app uses
|
||||
the design system's `Accordion` (title = "Sommerräder"/"Winterräder", summary = "Ersetzt am ... · N km"),
|
||||
expanding to a read-only `Werteliste` with a "Bearbeiten" button that swaps in an edit form (mirrors
|
||||
`TankFormular`'s style) — plus a destructive "Löschen" button. The panel reuses its own existing
|
||||
`acc-h`/`acc-b`/`data-acc` accordion mechanism (same as the trips/tankvorgaenge year/month lists) with
|
||||
always-inline-editable fields (`data-rfa="id|feld"`, parallel to `data-rf`) that call
|
||||
`reifen_archiv_aktualisieren` directly on change, plus a `data-reifenarchivloeschen` button.
|
||||
`profilAdapter.ts` gained a `ReifenArchivEintrag` type and `Fahrzeug.reifen.archiv`; `profilZuFahrzeug()`
|
||||
reads it straight off the profile (`?? []`), and `zusammenfuehren()` needed no change — it clones the raw
|
||||
profile first and only ever touches `aktiv`/`anzugsmoment_nm`/`wechsel`/`saetze`, so `archiv` survives
|
||||
untouched exactly like it already did for every other field this function doesn't know about.
|
||||
|
||||
Verified: `py_compile` clean on all six touched backend files (`einstellungen.py`, `ablage.py`,
|
||||
`batterie.py`, `const.py`, `dienste.py`, `reifen.py`) plus `services.yaml` entries added for all four new
|
||||
services; `node --check` clean on the panel JS; companion-app `tsc --noEmit` clean and full suite green at
|
||||
**146/146** (one new test — the existing "every registered page renders with sample data" smoke test picked
|
||||
up `battliste` automatically); `npm run build` and `npm run ota` both succeeded (OTA bundle rebuilt at
|
||||
`2026.8.25.4`, sha256 `9d5ebc2a62da4bbddcd766a462726bb51a213ea4095e367e88a8e5d321a9f8e4`). Manifest bumped
|
||||
`2026.8.25.2` → `.3` (backend) → `.4` (frontend + OTA), both restarts in `audi_ha_test` confirmed clean via
|
||||
`"Audi Dashboard ... eingerichtet"` with no tracebacks, including the periodic battery-check log line
|
||||
firing without error against the new `AUSSENTEMP_SENSOR` code path. **Not verified live in a browser** —
|
||||
the setup-menu entry for `AUSSENTEMP_SENSOR`, the new list screens, the icon substitutions' actual pixel
|
||||
rendering, and the archive accordion/edit flow were none of them clicked through in this round (a
|
||||
browser-tooling networking issue blocked reaching the test instance's UI, same blocker noted in section Q).
|
||||
This entire round rests on static analysis, compiler/test-suite checks, and clean service-registration logs
|
||||
— not on having seen any of it render.
|
||||
|
||||
## S. Live browser access to the test instance, a "Generatorspannung" remark, and two real bugs section R's
|
||||
static-only verification missed (2026.8.25.5–.8)
|
||||
|
||||
**The owner logged this session into the test instance's browser at `http://localhost:18123` (not the
|
||||
`:8123` used earlier - a different, working port for this environment).** This unblocked live verification
|
||||
for the first time since the FMM003 investigation's `/profile/security` refusal (section P) — worth noting
|
||||
for future sessions: try `:18123` before assuming the browser tooling can't reach this project's test
|
||||
container.
|
||||
|
||||
**Generator-voltage remark (2026.8.25.5):** `AGM_RUHE_MAX_V = 12.8` (the resting-vs-alternator-voltage
|
||||
threshold, already used by the diagram's own point filter and the SOC estimate) was not applied to the new
|
||||
measurement list from section R — a day whose minimum was never actually measured at rest still displayed
|
||||
next to a date/time as if it were one. Companion-app: exported the constant from `Batterie.tsx`, added a
|
||||
`Pill` reading "Generatorspannung" in `BatterieListe.tsx` when `min > AGM_RUHE_MAX_V`. Panel: same threshold
|
||||
already in scope in `vBatterieliste()`, added a `.pill`-styled badge under the date in the `.v` column.
|
||||
|
||||
**Live verification then immediately found two real defects that every static check in section R had
|
||||
missed** — `py_compile`/`tsc`/`node --check`/the test suite all passed because none of them render CSS:
|
||||
|
||||
1. **Archive edit fields visually truncated ("Continenta", "SportConta", "275/30 R2").** `vReifenArchiv()`'s
|
||||
`feld()` helper unconditionally wrapped every input in `<span class="mitEinheit">` — a class meant for
|
||||
short number+unit pairs (km, Nm, bar) that hard-codes `input{width:96px}`. None of the fields that
|
||||
actually used this helper (marke/modell/mass/dot/kommentar) needed a unit at all, so the wrapper was pure
|
||||
accident, not a deliberate width choice. Fixed by dropping `mitEinheit` from that helper entirely,
|
||||
matching the plain `<input>` the live (non-archived) season fields already use one screen up. Confirmed
|
||||
live: all three previously-clipped fields now render in full.
|
||||
2. **Owner follow-up, also confirmed live before and after:** the archive accordion's collapsed summary
|
||||
line squeezed `4.542 km` into a `<small>` immediately after the "Ersetzt am" date, and separately asked
|
||||
for the Kommentar/Notiz field specifically to get more room. Both fixed the same way in both codebases:
|
||||
Kommentar/Notiz now renders label-above-input at full width (`.feld--breit` in the panel CSS; a
|
||||
bypassed-`Feld` block in companion-app) instead of sharing a row with its label like every other short
|
||||
field — and the collapsed summary now shows the km figure at title size/color (`.acc-h .k`/
|
||||
`.ads-acc-h__k`-equivalent styling) with the date dropped to its own smaller line below, instead of the
|
||||
two being run together.
|
||||
|
||||
**Lesson for this project going forward, worth remembering deliberately:** a clean compile/test pass is not
|
||||
evidence a layout is correct — none of the tooling in this repo renders CSS or checks visual width. Section
|
||||
R shipped a real, user-visible truncation bug behind a fully green test suite. When browser access is
|
||||
available (now confirmed reachable at `:18123`), prefer at least one live screenshot of any new or changed
|
||||
input-heavy screen over relying on compiler output alone.
|
||||
|
||||
Verified: panel `node --check` clean at every step; companion-app `tsc --noEmit` clean, suite green at
|
||||
146/146, `npm run build`/`npm run ota` succeeded. Manifest `2026.8.25.4` → `.5` (Generatorspannung) → `.6`
|
||||
(mitEinheit fix) → `.7` (Kommentar width + archive header restyle, panel) → `.8` (same two, companion-app
|
||||
parity + final OTA rebuild, sha256 `464c294c6c07dcb636a8ea3bd93c7e525b21722defb41f573e2b31fefade49ea`).
|
||||
Every restart in `audi_ha_test` confirmed clean via log, **and this time also confirmed live in the browser**
|
||||
at each step from `.6` onward — screenshots taken of the battery list (Generatorspannung pill rendering
|
||||
correctly, including a real entry below the threshold correctly *not* tagged), the Statistik tab's `polls-s`
|
||||
icon, and the Reifen archive section before and after both fixes.
|
||||
|
||||
---
|
||||
|
||||
## Working conventions (observed — keep them)
|
||||
|
||||
Reference in New Issue
Block a user