"""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 entitaeten import frontend_veroeffentlichung import profil BACKUP_ORDNER = f"{profil.BASIS}/backups" # entitaeten.json gehört dazu: Ohne sie wäre nach einer Wiederherstellung die # komplette Sensor-Zuordnung aus dem Setup-Menü verloren, und weil sie sonst # nirgends abgelegt ist, gäbe es nichts zurückzuholen. _DATEIEN = [ "fahrzeugprofil.json", "fahrten.jsonl", "tankvorgaenge.jsonl", "entitaeten.json", ] 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, entitaeten_json=None): """Stellt ein über "Backup exportieren" heruntergeladenes Backup wieder her - überschreibt Profil, Fahrten, Tankvorgänge und die Sensor-Zuordnung komplett. Aufruf als pyscript.audi_dashboard_backup_wiederherstellen. entitaeten_json ist optional: ältere Sicherungen, die vor dem Setup-Menü entstanden sind, enthalten den Abschnitt nicht - dann bleibt die aktuelle Zuordnung unangetastet, statt sie zu leeren.""" 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) if entitaeten_json: zuordnung = json.loads(entitaeten_json) if isinstance(entitaeten_json, str) else entitaeten_json entitaeten.overrides_schreiben(zuordnung) entitaeten.overrides_anwenden() frontend_veroeffentlichung.alles_veroeffentlichen() log.info("audi_dashboard: Backup wiederhergestellt")