Files
audi-app/homeassistant/pyscript/backup.py
T
Paul Nothaft 8e268f044d Phase 2: Doku an Codestand angleichen, profil_lesen haerten
Doku-Drift behoben: die Statistik-Seite rechnet laengst echt (Behauptung
stand an drei Stellen), INSTALL.md nannte in Schritt 4 vier Variablennamen,
die es nie gab, README erwaehnte die entfernte 97-Prozent-Volltankungsregel
und liess fuenf pyscript-Dateien in der Uebersicht aus. Obsoleter
TODO-Kommentar in belegverarbeitung.py entfernt.

profil_lesen() gibt bei fehlender oder beschaedigter Profildatei None
zurueck statt zu werfen; alle sieben Aufrufstellen fangen den Fall ab.
An der Testinstanz geprueft: Datei entfernt, es folgt eine verstaendliche
Fehlermeldung mit Verweis auf INSTALL.md statt eines Tracebacks pro
Trigger-Durchlauf, Home Assistant laeuft normal weiter.
2026-08-11 10:48:33 +02:00

97 lines
3.7 KiB
Python

"""Backup-Funktion für Fahrzeugprofil, Fahrten und Tankvorgänge.
Manuell über "Backup jetzt erstellen" in den Einstellungen oder automatisch
je nach einstellungen.backup_intervall im Fahrzeugprofil (aus/täglich/
wöchentlich/monatlich) - immer um 04:00 Uhr, wenn eingestellt. Ein einzelner
täglicher Trigger um 04:00 genügt für alle drei Intervalle: wöchentlich läuft
nur montags, monatlich nur am Monatsersten, täglich jeden Tag - so reicht eine
einzige Trigger-Registrierung statt drei.
Jedes Backup ist ein eigener Zeitstempel-Unterordner mit Kopien der drei
Bestände (siehe profil.py), keine ZIP-Datei - das würde den vorhandenen
task.executor(io.open, ...)-Weg (siehe dessen Kopfkommentar in profil.py)
unnötig verkomplizieren. shutil.copy() ist wie io.open eine echte externe
Funktion und läuft deshalb über denselben task.executor-Weg.
"Backup exportieren"/"importieren" in der Oberfläche laufen dagegen rein
über den Browser (aktuell geladenes Profil + Fahrten + Tankvorgänge als eine
JSON-Datei, siehe audi-dashboard-app.js) - audi_dashboard_backup_wiederherstellen()
hier ist nur das Gegenstück zum Import, das die drei Bestände wieder
komplett überschreibt.
"""
import datetime
import json
import os
import shutil
import frontend_veroeffentlichung
import profil
BACKUP_ORDNER = f"{profil.BASIS}/backups"
_DATEIEN = ["fahrzeugprofil.json", "fahrten.jsonl", "tankvorgaenge.jsonl"]
def _backup_jetzt():
ziel = f"{BACKUP_ORDNER}/{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}"
os.makedirs(ziel, exist_ok=True)
for name in _DATEIEN:
quelle = f"{profil.BASIS}/{name}"
if os.path.exists(quelle):
task.executor(shutil.copy, quelle, f"{ziel}/{name}")
return ziel
def _letztes_backup_vermerken():
p = profil.profil_lesen()
if p is None:
return
p.setdefault("einstellungen", {})["letztes_backup"] = datetime.datetime.now().isoformat()
profil.profil_schreiben(p)
frontend_veroeffentlichung.profil_veroeffentlichen()
@service
def audi_dashboard_backup_jetzt():
"""Erstellt sofort ein Backup. Aufruf als pyscript.audi_dashboard_backup_jetzt."""
ziel = _backup_jetzt()
_letztes_backup_vermerken()
log.info(f"audi_dashboard: Backup erstellt unter {ziel}")
@time_trigger("cron(0 4 * * *)")
def _automatisches_backup():
p = profil.profil_lesen()
if p is None:
return
intervall = p.get("einstellungen", {}).get("backup_intervall", "aus")
heute = datetime.date.today()
faellig = (
intervall == "taeglich"
or (intervall == "woechentlich" and heute.weekday() == 0)
or (intervall == "monatlich" and heute.day == 1)
)
if not faellig:
return
ziel = _backup_jetzt()
_letztes_backup_vermerken()
log.info(f"audi_dashboard: automatisches Backup ({intervall}) erstellt unter {ziel}")
@service
def audi_dashboard_backup_wiederherstellen(profil_json=None, fahrten_json=None, tankvorgaenge_json=None):
"""Stellt ein über "Backup exportieren" heruntergeladenes Backup wieder
her - überschreibt Profil, Fahrten und Tankvorgänge komplett. Aufruf als
pyscript.audi_dashboard_backup_wiederherstellen."""
if profil_json:
p = json.loads(profil_json) if isinstance(profil_json, str) else profil_json
profil.profil_schreiben(p)
if fahrten_json is not None:
fahrten = json.loads(fahrten_json) if isinstance(fahrten_json, str) else fahrten_json
profil.fahrten_schreiben(fahrten)
if tankvorgaenge_json is not None:
tankvorgaenge = json.loads(tankvorgaenge_json) if isinstance(tankvorgaenge_json, str) else tankvorgaenge_json
profil.tankvorgaenge_schreiben(tankvorgaenge)
frontend_veroeffentlichung.alles_veroeffentlichen()
log.info("audi_dashboard: Backup wiederhergestellt")