1354ca6b06
HACS kann laut eigener Dokumentation grundsätzlich nicht mit privaten GitHub-Repositories arbeiten (hacs.xyz/docs/faq/private_repositories) - keine Ausnahme für Tokens oder verbundene Konten. Meine frühere Annahme, HACS käme damit zurecht, wenn es unter dem richtigen Konto angemeldet ist, war falsch. Da das Repository aus Lizenzgründen privat bleiben muss (Audi-Hausschrift, Typenschilder), ist install.ps1 damit nicht die Rückfallebene, sondern der einzige Installationsweg - README, INSTALL.md, ANLEITUNG.md, install.ps1 und VERSIONIERUNG.md korrigiert. Oberflächen-Updates für die iOS-App laufen jetzt ohne Xcode: @capgo/capacitor-updater eingebaut, ein Update-Abschnitt in den Einstellungen lädt ein neues Bündel und tauscht die Oberfläche aus. Kein Selbstlauf (autoUpdate: false) - nur auf Tastendruck, nie während der Benutzung. Das Bündel liegt in der Integration selbst (custom_components/audi_dashboard/frontend/app/), nicht unter /local/: so reist es bei jeder Installation automatisch mit, ohne zweiten Auslieferungsweg. Gebaut von companion-app/scripts/ota-paket.ps1 (neuer Befehl: npm run ota), gemeldet über sensor.audi_dashboard_app_version (neues Feld daten.buendel). Ein echter Bug beim Bauen gefunden: [IO.Compression.ZipFile]::CreateFrom- Directory schreibt unter Windows PowerShell 5.1 Backslashes in die Zip-Einträge - iOS hätte das Archiv falsch entpackt. Behoben, indem die Einträge von Hand mit "/" geschrieben werden. Rückfallebene: notifyAppReady() läuft erst, wenn React nachweislich gerendert hat (App.tsx). Kommt diese Meldung nicht, rollt das Plugin nach 20 Sekunden von selbst auf das vorherige Bündel zurück. Am laufenden Testcontainer verifiziert: die ausgelieferte Zip hasht exakt auf den in bundle.json hinterlegten Wert, 13 Einträge, index.html in der Wurzel, keine Backslashes, keine Beschädigung. tsc sauber, 117/117 Tests (5 davon neu für buendelPasst() - dabei eine echte Lücke gefunden: die Funktion hätte bei unbekannter eigener Version fälschlich ein Update angeboten, jetzt genauso vorsichtig wie versionVergleichen). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
226 lines
11 KiB
PowerShell
226 lines
11 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Installiert "Mein Audi" (DataMetric360) als Home-Assistant-Integration -
|
|
der Weg ohne HACS.
|
|
|
|
.BESCHREIBUNG
|
|
Kopiert genau einen Ordner:
|
|
|
|
custom_components\audi_dashboard\ -> <Ziel>\custom_components\
|
|
|
|
Mehr ist nicht nötig. Alles, was früher an dieser Stelle von Hand gemacht
|
|
werden musste, macht die Integration inzwischen selbst: sie meldet ihr Panel
|
|
an, liefert ihre Oberflächen-Dateien selbst aus, legt beim ersten Start ein
|
|
Fahrzeugprofil aus der Vorlage an und bringt pypdf über ihre manifest.json
|
|
mit, das Home Assistant beim ersten Laden nachinstalliert.
|
|
|
|
WOFÜR ES DIESES SKRIPT ÜBERHAUPT GIBT
|
|
--------------------------------------
|
|
HACS scheidet für dieses Repository aus, und zwar endgültig: laut eigener
|
|
Dokumentation (hacs.xyz/docs/faq/private_repositories) kann HACS
|
|
"grundsätzlich nicht" mit privaten GitHub-Repositories arbeiten - ohne
|
|
Ausnahme für Tokens oder verbundene Konten. Das Projekt wird zwar von der
|
|
eigenen Gitea-Instanz nach github.com/T130B/DM360 gespiegelt, aber das
|
|
Repository bleibt privat: es enthält die Audi-Hausschrift und die
|
|
Typenschilder, die nur für diese eine private Installation lizenziert
|
|
sind, und öffentlich machen ist deshalb keine Option.
|
|
|
|
Dieses Skript ist damit nicht die Rückfallebene, sondern der einzige Weg.
|
|
Es installiert exakt den Ordner, den auch HACS installieren würde, wenn es
|
|
könnte - dieselbe Prüfung, ohne die HACS-Voraussetzung.
|
|
|
|
SICHERHEIT GEGENÜBER DER BESTEHENDEN HA-INSTALLATION
|
|
----------------------------------------------------
|
|
Die riskanteste Stelle der früheren Fassung gibt es nicht mehr: sie musste
|
|
die configuration.yaml ergänzen (pyscript:, panel_custom:), und eine kaputte
|
|
configuration.yaml ist der eine Weg, auf dem ein Installer Home Assistant am
|
|
Starten hindern kann. Diese Fassung fasst die Datei überhaupt nicht mehr an.
|
|
|
|
Was bleibt, ist nachprüfbar:
|
|
- Geschrieben wird ausschließlich in <Ziel>\custom_components\audi_dashboard.
|
|
Kein anderer Pfad wird angefasst - nicht .storage\, nicht
|
|
configuration.yaml, nicht automations.yaml, nicht www\, nicht
|
|
audi_dashboard\ (die Fahrzeugdaten).
|
|
- Entfernt wird nur der eigene Ordner, und nur, wenn darin eine
|
|
manifest.json mit "domain": "audi_dashboard" liegt. Ein fremder Ordner
|
|
unter diesem Namen führt zum Abbruch, nicht zum Löschen.
|
|
- Es startet Home Assistant nicht neu und greift nicht in den laufenden
|
|
Betrieb ein.
|
|
- -Pruefen zeigt den kompletten Ablauf, ohne irgendetwas zu schreiben.
|
|
Im Zweifel damit anfangen.
|
|
|
|
Warum der Zielordner vor dem Kopieren geleert wird (und nicht nur
|
|
überschrieben): bleibt eine Datei aus einer älteren Fassung liegen, die es
|
|
im neuen Stand nicht mehr gibt, lädt Home Assistant sie trotzdem mit. Das
|
|
ist genau der Fehler, den man hinterher am schwersten findet. HACS macht es
|
|
aus demselben Grund so.
|
|
|
|
Die Fahrzeugdaten liegen woanders (<Ziel>\audi_dashboard\) und werden von
|
|
diesem Skript nie berührt - ein Update kann sie deshalb gar nicht treffen.
|
|
|
|
.PARAMETER Ziel
|
|
config-Verzeichnis der HA-Instanz, z. B. "\\homeassistant.local\config"
|
|
(Samba-Add-on) oder ein lokal gemounteter Pfad. Ohne Angabe sucht das
|
|
Skript die üblichen Samba-Namen selbst ab.
|
|
|
|
.PARAMETER Pruefen
|
|
Nur anzeigen, was passieren würde - es wird nichts geschrieben.
|
|
|
|
.BEISPIEL
|
|
.\install.ps1
|
|
.\install.ps1 -Ziel "\\192.168.1.50\config"
|
|
.\install.ps1 -Pruefen
|
|
#>
|
|
param(
|
|
[string]$Ziel,
|
|
[switch]$Pruefen
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
$hier = $PSScriptRoot
|
|
|
|
function Schritt($text) { Write-Host "`n$text" -ForegroundColor Cyan }
|
|
function Gut($text) { Write-Host " [ok] $text" -ForegroundColor Green }
|
|
function Info($text) { Write-Host " [info] $text" -ForegroundColor DarkGray }
|
|
function Warnung($text) { Write-Host " [!] $text" -ForegroundColor Yellow }
|
|
|
|
$restliste = New-Object System.Collections.ArrayList
|
|
|
|
Write-Host ""
|
|
Write-Host " Mein Audi - Installation" -ForegroundColor White
|
|
Write-Host " ========================" -ForegroundColor White
|
|
if ($Pruefen) { Warnung "Pruefmodus - es wird nichts geschrieben." }
|
|
|
|
# ------------------------------------------------------------ Quelle finden
|
|
# Zwei Lagen, damit sowohl der Aufruf aus dem Projektordner heraus als auch
|
|
# ein separat weitergegebenes Paket funktioniert.
|
|
$quellKandidaten = @(
|
|
(Join-Path $hier "custom_components\audi_dashboard"),
|
|
(Join-Path $hier "..\..\custom_components\audi_dashboard")
|
|
)
|
|
$quelle = $null
|
|
foreach ($k in $quellKandidaten) {
|
|
if (Test-Path (Join-Path $k "manifest.json")) { $quelle = (Resolve-Path $k).Path; break }
|
|
}
|
|
if (-not $quelle) {
|
|
throw "custom_components\audi_dashboard nicht gefunden - dieses Skript gehört in den Projektordner (oder das Paket daneben)."
|
|
}
|
|
$version = (Get-Content (Join-Path $quelle "manifest.json") -Raw | ConvertFrom-Json).version
|
|
Gut "Quelle: $quelle (Version $version)"
|
|
|
|
# ---------------------------------------------------------------- Ziel finden
|
|
if (-not $Ziel) {
|
|
Schritt "Suche Home Assistant ..."
|
|
# Die Reihenfolge ist Absicht: der kurze Name antwortet in den meisten
|
|
# Heimnetzen schneller als der .local-Name über mDNS.
|
|
$kandidaten = @(
|
|
"\\homeassistant\config",
|
|
"\\homeassistant.local\config",
|
|
"\\hassio\config"
|
|
)
|
|
foreach ($k in $kandidaten) {
|
|
Info "probiere $k"
|
|
if (Test-Path $k) { $Ziel = $k; break }
|
|
}
|
|
if (-not $Ziel) {
|
|
Write-Host ""
|
|
Warnung "Keine HA-Instanz automatisch gefunden."
|
|
Write-Host " Bitte den config-Pfad angeben, z. B. \\192.168.1.50\config"
|
|
Write-Host " (Samba-Share-Add-on in HA muss laufen und verbunden sein.)"
|
|
Write-Host ""
|
|
$Ziel = Read-Host " config-Pfad"
|
|
if (-not $Ziel) { throw "Kein Ziel angegeben - Abbruch." }
|
|
}
|
|
}
|
|
|
|
if (-not (Test-Path $Ziel)) {
|
|
throw "Ziel nicht erreichbar: $Ziel - Samba-Share verbunden? Pfad korrekt?"
|
|
}
|
|
|
|
# Ein config-Verzeichnis ohne configuration.yaml ist mit hoher Wahrscheinlichkeit
|
|
# der falsche Ordner - lieber hier abbrechen als Dateien irgendwohin streuen.
|
|
if (-not (Test-Path (Join-Path $Ziel "configuration.yaml"))) {
|
|
throw "In $Ziel liegt keine configuration.yaml - ist das wirklich das config-Verzeichnis von HA?"
|
|
}
|
|
Gut "Ziel: $Ziel"
|
|
|
|
# ------------------------------------------------------- Zielordner prüfen
|
|
$zielOrdner = Join-Path $Ziel "custom_components\audi_dashboard"
|
|
$vorhandeneVersion = $null
|
|
if (Test-Path $zielOrdner) {
|
|
$zielManifest = Join-Path $zielOrdner "manifest.json"
|
|
if (-not (Test-Path $zielManifest)) {
|
|
throw "In $zielOrdner liegt keine manifest.json. Das ist nicht unser Ordner - Abbruch, es wird nichts angefasst."
|
|
}
|
|
$vorhandenesManifest = Get-Content $zielManifest -Raw | ConvertFrom-Json
|
|
if ($vorhandenesManifest.domain -ne "audi_dashboard") {
|
|
throw "$zielOrdner gehört zur Integration '$($vorhandenesManifest.domain)', nicht zu 'audi_dashboard' - Abbruch."
|
|
}
|
|
$vorhandeneVersion = $vorhandenesManifest.version
|
|
Info "bereits installiert: Version $vorhandeneVersion"
|
|
}
|
|
|
|
# ----------------------------------------------------------------- Kopieren
|
|
Schritt "Integration kopieren"
|
|
if ($Pruefen) {
|
|
if ($vorhandeneVersion) { Info "würde ersetzen: $zielOrdner (Version $vorhandeneVersion -> $version)" }
|
|
else { Info "würde anlegen: $zielOrdner (Version $version)" }
|
|
Info "würde sonst nichts anfassen - keine configuration.yaml, keine Fahrzeugdaten"
|
|
} else {
|
|
New-Item -ItemType Directory -Force -Path (Join-Path $Ziel "custom_components") | Out-Null
|
|
if (Test-Path $zielOrdner) {
|
|
# Die Prüfung oben hat bestätigt, dass das unser Ordner ist.
|
|
Remove-Item $zielOrdner -Recurse -Force
|
|
}
|
|
Copy-Item $quelle $zielOrdner -Recurse -Force
|
|
# Übersetzte Reste einer früheren Fassung gehören nicht ins Ziel.
|
|
Get-ChildItem $zielOrdner -Recurse -Directory -Filter "__pycache__" |
|
|
ForEach-Object { Remove-Item $_.FullName -Recurse -Force }
|
|
|
|
# Rücklesen: liegt im Ziel wirklich das, was gemeint war?
|
|
$kontrolle = Join-Path $zielOrdner "manifest.json"
|
|
if (-not (Test-Path $kontrolle)) {
|
|
throw "Nach dem Kopieren fehlt $kontrolle - die Installation ist unvollständig."
|
|
}
|
|
$geschrieben = (Get-Content $kontrolle -Raw | ConvertFrom-Json).version
|
|
if ($geschrieben -ne $version) {
|
|
throw "Nach dem Kopieren steht Version '$geschrieben' statt '$version' im Ziel - die Installation ist unvollständig."
|
|
}
|
|
$anzahl = (Get-ChildItem $zielOrdner -Recurse -File).Count
|
|
Gut "custom_components\audi_dashboard (Version $version, $anzahl Dateien)"
|
|
}
|
|
|
|
# --------------------------------------------------------------- Restliste
|
|
if (-not $vorhandeneVersion) {
|
|
[void]$restliste.Add("Home Assistant neu starten: Einstellungen -> System -> Neu starten. (Beim ersten Start ladt HA die Abhaengigkeit pypdf nach - das kann eine Minute dauern.)")
|
|
[void]$restliste.Add("Integration hinzufuegen: Einstellungen -> Geraete & Dienste -> Integration hinzufuegen -> 'Audi Dashboard'. Danach steht 'Mein Audi' in der Seitenleiste.")
|
|
[void]$restliste.Add("In der App: Einstellungen -> Fahrzeug einrichten -> Setup - Sensoren zuordnen. Im Auslieferstand ist KEIN Sensor vorbelegt; zwingend fuer die Fahrterkennung ist der Zuendungs-/ACC-Sensor (binary_sensor, meist vom Teltonika FMM003). Ein Neustart ist dafuer nicht mehr noetig - Aenderungen wirken sofort.")
|
|
} else {
|
|
[void]$restliste.Add("Home Assistant neu starten: Einstellungen -> System -> Neu starten. (Oder kuerzer: Einstellungen -> Geraete & Dienste -> Audi Dashboard -> Neu laden.)")
|
|
}
|
|
|
|
# Bewusst nicht automatisch eingefügt: der recorder-Block ist eine Entscheidung
|
|
# über den Plattenplatz der Instanz (ein Jahr Fahrzeugverlauf sind grob 1-1,5 GB,
|
|
# siehe Kopf von recorder_snippet.yaml), und viele Instanzen haben bereits einen
|
|
# eigenen recorder:-Block mit anderen Einstellungen. Zusammenführen ist Handarbeit.
|
|
[void]$restliste.Add("ZEITKRITISCH - Datenaufbewahrung: den Block aus recorder_snippet.yaml in die configuration.yaml uebernehmen. Home Assistant loescht Sensor-Verlaeufe sonst nach 10 Tagen; was weg ist, laesst sich auch mit 'Daten importieren aus Home Assistant' nicht mehr nachtragen. Je frueher der Block drin ist, desto mehr Vergangenheit bleibt erhalten. VORHER Einstellungen -> System -> Speicher pruefen: ein Jahr Verlauf braucht grob 1-1,5 GB. Bei wenig freiem Platz (SD-Karte, kleine eMMC) mit purge_keep_days: 90 anfangen - Details im Kopf der Datei.")
|
|
[void]$restliste.Add("Optional, sobald die Sensoren zugeordnet sind: Einstellungen -> Einrichten -> 'Daten importieren aus Home Assistant' holt Fahrten, Tankvorgaenge und Spannungswerte aus dem bereits aufgezeichneten HA-Verlauf nach.")
|
|
|
|
Write-Host ""
|
|
if ($Pruefen) {
|
|
Write-Host " Pruefmodus beendet - es wurde nichts geschrieben." -ForegroundColor Yellow
|
|
} else {
|
|
Write-Host " Die Integration ist installiert." -ForegroundColor Green
|
|
}
|
|
Write-Host ""
|
|
Write-Host " Das fehlt noch:" -ForegroundColor White
|
|
$nr = 1
|
|
foreach ($punkt in $restliste) {
|
|
Write-Host " $nr. $punkt"
|
|
$nr++
|
|
}
|
|
Write-Host ""
|
|
Write-Host " Fuer spaetere Updates reicht derselbe Aufruf noch einmal." -ForegroundColor White
|
|
Write-Host " Die Fahrzeugdaten unter audi_dashboard\ bleiben dabei unangetastet."
|
|
Write-Host ""
|