diff --git a/AGENTS.md b/AGENTS.md index 5056536..d42deb3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11797,3 +11797,60 @@ Die Gestaltung des zweiten Abschnitts gegengeprueft, indem einer eingesetzt wurde: Haarlinie 0.8px, 16px Abstand und 16px Polster darueber, Abschnittskopf 14px ueber seinem Inhalt. Der Abschnitt selbst ist nur in der nativen Huelle zu sehen - im Browser ist `otaMoeglich()` falsch. + +## CX. Die Integration bot Rueckschritte als Update an (2026.9.5.19) + +Gemeldet: *"Warum wird eine aeltere Version angeboten? .16 ist aelter als +.18"*. In `aktualisierung.py` stand: + + "verfuegbar": remote_version != eigene_version + +Reine Ungleichheit, ohne Richtung. Lief die Instanz einer Veroeffentlichung +voraus - waehrend der Entwicklung der Normalfall -, bot die Integration an, +sich auf die AELTERE Fassung zu "aktualisieren". + +Es ist derselbe Fehler, der am 04.09.2026 fuer die App behoben wurde +(`appVersion.ts`: *"erkannt werden soll eine NEUERE Fassung und keine +andere"*), nur auf der anderen Seite - und er blieb dort stehen, weil damals +nur die App angesehen wurde. + +`ist_neuer()` ist jetzt das Gegenstueck zu `versionOrdnung()`, mit denselben +drei Eigenschaften: + +* Fehlende Stellen zaehlen als 0, `2026.9.4` und `2026.9.4.0` sind derselbe + Stand. +* Kein `int()` mit Vorabschnitt - "4b" darf nicht klaglos als 4 gelesen werden, + sonst entsteht genau die scheingenaue Reihenfolge, die vermieden werden soll. +* Laesst sich keine Reihenfolge bilden (Formatwechsel), gilt die Fassung als + verfuegbar: die Oberflaeche sagt dann, dass etwas abweicht, aber nicht in + welche Richtung - besser als eine Aenderung zu verschweigen. + +Sechs neue Faelle in `tests/aktualisierung/test_aktualisierung.py`, 79 Tests +gruen. Live gegengeprueft: Gitea auf .18, Instanz auf .19 - gemeldet wird +"aktuell" statt eines Rueckschritts. + +### Die Kachel wurde dabei schlanker + +Vorgabe des Eigentuemers: *"Statt Installiert 'Home-Assistant-Integration' zu +schreiben. Dann haette der User die Sicht: Was ist in welcher Version vorhanden +auf seinem Geraet."* Die Zeile benennt jetzt selbst, was sie zeigt: + + Home-Assistant-Integration 2026.9.5.19 + aktuell geprueft 05.09.2026, 11:32 Uhr + +Damit entfallen auch die Abschnitts-Ueberschriften "Integration"/"App" aus +CW - sie sagten dasselbe ein zweites Mal. Die beiden Bloecke trennt weiterhin +eine Haarlinie, und benannt sind sie durch ihre eigene Zeile. + +**"aktuell" erscheint nur nach einer Pruefung.** Vorher steht dort gar nichts: +gruen "aktuell" ohne Pruefung waere eine Behauptung ohne Grundlage, und der +Knopf "Auf Update pruefen" sagt den Zustand ohnehin. Es gibt keinen +automatischen Takt - geprueft wird nur auf Knopfdruck (nachgesehen, kein +`async_track_time_interval` dafuer). + +Gemessen in beiden: Farbe `rgb(52,199,89)` bzw. `rgb(48,209,88)` - das ist +`--ok` im jeweiligen Thema. + +**Offen, zur Entscheidung:** "Home-Assistant-Integration" bricht als Beschriftung +auf Telefonbreite in zwei Zeilen um. Lesbar, aber unruhig. "Integration" allein +wuerde einzeilig passen. diff --git a/companion-app/src/screens/Einstellungen.tsx b/companion-app/src/screens/Einstellungen.tsx index 0af1c0b..9567f6c 100644 --- a/companion-app/src/screens/Einstellungen.tsx +++ b/companion-app/src/screens/Einstellungen.tsx @@ -748,21 +748,15 @@ export function Einstellungen({ Version + {/* Die Zeile benennt selbst, WAS in welcher Fassung auf dem Geraet + liegt - vorher hiess das Label "Installiert" und der Gegenstand + stand klein darunter. Damit braucht der Abschnitt auch keine + Ueberschrift mehr: sie saegte dasselbe ein zweites Mal (Vorgabe + des Eigentuemers, 05.09.2026: "damit wird es nochmal schlanker"). */}
- {/* Nur wenn darunter wirklich ein zweiter Abschnitt folgt. Ohne den - staende "Integration" allein unter "Version" - eine Unterteilung - ohne zweiten Teil, genau wie im Panel, das den App-Abschnitt gar - nicht kennt. */} - {otaMoeglich() && Integration} - - } - /> + } + /> {/* HIG "Loading": Netzwerk zu Gitea plus Entpacken dauert unbestimmt lang, ohne verlässliche Fortschrittsangabe - ein laufender Indikator statt eines nur deaktivierten Knopfes verhindert, dass @@ -865,12 +859,7 @@ export function Einstellungen({ {otaMoeglich() && (
- App - - } - /> + } /> {otaUpdateVerfuegbar && otaBuendel ? ( <> dict[str, str]: return {"Authorization": f"token {token}"} +def _versionsteile(version: str) -> list[int] | None: + """Zerlegt `2026.9.4.17` in [2026, 9, 4, 17]. + + `None`, sobald ein Teil keine reine Ziffernfolge ist - dann wird nicht + sortiert. Bewusst kein `int()` mit Vorabschnitt: das läse "4b" klaglos als + 4 und erzeugte genau die scheingenaue Reihenfolge, die hier vermieden + werden soll. Wortgleich mit `teile()` in + companion-app/src/daten/appVersion.ts.""" + if not version: + return None + zahlen: list[int] = [] + for stueck in version.split("."): + if not stueck.isdigit(): + return None + zahlen.append(int(stueck)) + return zahlen + + +def ist_neuer(kandidat: str, bisher: str) -> bool | None: + """Ob `kandidat` nachweislich neuer ist als `bisher`. + + `None` heißt "nicht zu entscheiden" - verschieden, aber nicht in eine + Reihenfolge zu bringen (Formatwechsel). Fehlende Stellen zählen als 0, + damit `2026.9.4` und `2026.9.4.0` denselben Stand bezeichnen. + + Gegenstück zu `versionOrdnung()` in appVersion.ts. Der Grund ist derselbe + und dort ausführlich vermerkt: bis zum 05.09.2026 stand hier + `remote_version != eigene_version`, also reine Ungleichheit ohne Richtung. + Lief die Instanz einer Veröffentlichung voraus - während der Entwicklung + der Normalfall -, bot die Integration an, sich auf die ÄLTERE Fassung zu + "aktualisieren". Vom Eigentümer am 05.09.2026 gemeldet: „Warum wird eine + ältere Version angeboten? .16 ist älter als .18".""" + if not kandidat or not bisher: + return None + if kandidat == bisher: + return False + links = _versionsteile(kandidat) + rechts = _versionsteile(bisher) + if links is None or rechts is None: + return None + for i in range(max(len(links), len(rechts))): + l = links[i] if i < len(links) else 0 + r = rechts[i] if i < len(rechts) else 0 + if l != r: + return l > r + return False + + async def version_pruefen(hass: HomeAssistant, token: str, eigene_version: str) -> dict[str, Any]: """Fragt nur die manifest.json von Gitea ab (ein kleiner Request, kein Repo-Download) und vergleicht die Version gegen die installierte. @@ -120,7 +168,11 @@ async def version_pruefen(hass: HomeAssistant, token: str, eigene_version: str) raise AktualisierungsFehler(f"Antwort von Gitea nicht lesbar: {fehler}") from fehler return { - "verfuegbar": remote_version != eigene_version, + # Nur eine NACHWEISLICH neuere Fassung ist ein Update. Ist sie nicht + # in eine Reihenfolge zu bringen (None), gilt sie als verfuegbar - + # dann sagt die Oberflaeche, dass etwas abweicht, aber nicht in + # welche Richtung, statt eine Aenderung zu verschweigen. + "verfuegbar": ist_neuer(remote_version, eigene_version) is not False, "version": remote_version, "geprueft_am": datetime.datetime.now(datetime.timezone.utc).isoformat(), } diff --git a/custom_components/audi_dashboard/frontend/app/bundle.json b/custom_components/audi_dashboard/frontend/app/bundle.json index 62f7e9a..4cdb809 100644 --- a/custom_components/audi_dashboard/frontend/app/bundle.json +++ b/custom_components/audi_dashboard/frontend/app/bundle.json @@ -1 +1 @@ -{"version":"2026.9.5.18","sha256":"8b03fe0a871e5fc88b421146910832fbd73999ee9844000efbaf1b41a52ab603","bytes":324620,"gebaut":"2026-09-05T09:27:15Z"} \ No newline at end of file +{"version":"2026.9.5.19","sha256":"5490ca4a341da15dd210a13f84fb6941620d2974683b3c4280ea31ed87f0fb7c","bytes":324597,"gebaut":"2026-09-05T09:31:37Z"} \ No newline at end of file diff --git a/custom_components/audi_dashboard/frontend/app/bundle.zip b/custom_components/audi_dashboard/frontend/app/bundle.zip index 5e6201a..53305c0 100644 Binary files a/custom_components/audi_dashboard/frontend/app/bundle.zip and b/custom_components/audi_dashboard/frontend/app/bundle.zip differ diff --git a/custom_components/audi_dashboard/frontend/audi-dashboard-app.js b/custom_components/audi_dashboard/frontend/audi-dashboard-app.js index e419fb3..90ace62 100644 --- a/custom_components/audi_dashboard/frontend/audi-dashboard-app.js +++ b/custom_components/audi_dashboard/frontend/audi-dashboard-app.js @@ -3719,7 +3719,7 @@ function vEinst() { (Vorgabe des Eigentuemers, 04.09.2026). -->
Version
-
Installiert
${esc(APP_VERSION || "unbekannt")}Home-Assistant-Integration
+
Home-Assistant-Integration
${esc(APP_VERSION || "unbekannt")}
${(() => { const u = INTEGRATION_UPDATE; diff --git a/custom_components/audi_dashboard/manifest.json b/custom_components/audi_dashboard/manifest.json index 1b0198a..1158ee1 100644 --- a/custom_components/audi_dashboard/manifest.json +++ b/custom_components/audi_dashboard/manifest.json @@ -1,7 +1,7 @@ { "domain": "audi_dashboard", "name": "Audi Dashboard", - "version": "2026.9.5.18", + "version": "2026.9.5.19", "documentation": "https://gitea.nothaft.cloud/paul/audi-app/src/branch/main/README.md", "issue_tracker": "https://gitea.nothaft.cloud/paul/audi-app/issues", "codeowners": [ diff --git a/tests/aktualisierung/test_aktualisierung.py b/tests/aktualisierung/test_aktualisierung.py index 7ecc2e4..209c115 100644 --- a/tests/aktualisierung/test_aktualisierung.py +++ b/tests/aktualisierung/test_aktualisierung.py @@ -188,5 +188,41 @@ class AbgelehnteFaelle(unittest.TestCase): self._unangetastet() +class VersionsOrdnung(unittest.TestCase): + """Nur eine NACHWEISLICH neuere Fassung ist ein Update. + + Bis zum 05.09.2026 stand in version_pruefen() `remote_version != + eigene_version` - reine Ungleichheit ohne Richtung. Lief die Instanz einer + Veroeffentlichung voraus, bot die Integration an, sich auf die AELTERE + Fassung zu aktualisieren (vom Eigentuemer gemeldet: .16 wurde angeboten, + waehrend .18 lief).""" + + def test_neuere_fassung_ist_ein_update(self): + self.assertIs(a.ist_neuer("2026.9.5.18", "2026.9.5.16"), True) + self.assertIs(a.ist_neuer("2026.10.1.1", "2026.9.5.99"), True) + self.assertIs(a.ist_neuer("2027.1.1.1", "2026.12.31.9"), True) + + def test_aeltere_fassung_ist_keins(self): + self.assertIs(a.ist_neuer("2026.9.5.16", "2026.9.5.18"), False) + self.assertIs(a.ist_neuer("2026.9.4.26", "2026.9.5.1"), False) + + def test_gleichstand_ist_keins(self): + self.assertIs(a.ist_neuer("2026.9.5.18", "2026.9.5.18"), False) + + def test_fehlende_stellen_zaehlen_als_null(self): + self.assertIs(a.ist_neuer("2026.9.4", "2026.9.4.0"), False) + self.assertIs(a.ist_neuer("2026.9.4.1", "2026.9.4"), True) + + def test_nicht_sortierbar_bleibt_offen(self): + # Formatwechsel: lieber "nicht entscheidbar" als eine erfundene + # Reihenfolge. "4b" darf nicht klaglos als 4 gelesen werden. + self.assertIsNone(a.ist_neuer("2026.9.4b", "2026.9.4.1")) + self.assertIsNone(a.ist_neuer("v2", "2026.9.5.1")) + self.assertIsNone(a.ist_neuer("", "2026.9.5.1")) + + def test_zeichengleich_ist_gleich_auch_bei_fremdem_format(self): + self.assertIs(a.ist_neuer("beliebig", "beliebig"), False) + + if __name__ == "__main__": unittest.main()