diff --git a/haos-addon/config.yaml b/haos-addon/config.yaml index 175a694..5227c01 100644 --- a/haos-addon/config.yaml +++ b/haos-addon/config.yaml @@ -1,5 +1,5 @@ name: ShineBridge -version: "1.8.16" +version: "1.8.17" slug: shinebridge description: Growatt Wechselrichter lokal in Home Assistant — Modbus TCP via ShineLAN-X, MQTT Discovery, Web UI url: https://gitea.bitfire.work/retr0/shinebridge diff --git a/haos-addon/src/main.py b/haos-addon/src/main.py index 3ceb67a..3dbebb5 100644 --- a/haos-addon/src/main.py +++ b/haos-addon/src/main.py @@ -110,25 +110,34 @@ def _defaults() -> Dict[str, Any]: "z2m_base": "zigbee2mqtt", } +def _load_json_safe(path: str) -> Optional[Dict]: + """Lädt eine JSON-Datei; gibt None zurück wenn fehlend oder korrupt.""" + try: + with open(path) as f: + return json.load(f) + except Exception as e: + log.warning("JSON-Ladefehler %s: %s", path, e) + return None + + def load_config() -> Dict[str, Any]: cfg = _defaults() + # MQTT-Grundeinstellungen aus HAOS-Options (überschreibbar durch config.json) if os.path.exists(HA_OPTIONS_PATH): - try: - with open(HA_OPTIONS_PATH) as f: - ha = json.load(f) - for k in ("mqtt_broker", "mqtt_port", "mqtt_user", "mqtt_pass"): - if k in ha: - cfg[k] = ha[k] - except Exception as e: - log.warning("HA options Fehler: %s", e) - if os.path.exists(CONFIG_PATH): - try: - with open(CONFIG_PATH) as f: - cfg.update(json.load(f)) - except Exception as e: - log.warning("Config-Datei Fehler: %s", e) + ha = _load_json_safe(HA_OPTIONS_PATH) or {} + for k in ("mqtt_broker", "mqtt_port", "mqtt_user", "mqtt_pass"): + if k in ha: + cfg[k] = ha[k] + # Eigene persistente Config — Hauptdatei, dann Backup als Fallback + loaded = _load_json_safe(CONFIG_PATH) + if loaded is None and os.path.exists(CONFIG_PATH + ".bak"): + log.warning("config.json korrupt — lade Backup") + loaded = _load_json_safe(CONFIG_PATH + ".bak") + if loaded: + cfg.update(loaded) return cfg + def save_config(): data = { "mqtt_broker": State.mqtt_cfg.get("mqtt_broker", ""), @@ -150,8 +159,17 @@ def save_config(): "surplus_devices": State.surplus_devices_cfg, "z2m_base": State.z2m_base, } - with open(CONFIG_PATH, "w") as f: + # Backup der letzten guten Config anlegen + if os.path.exists(CONFIG_PATH): + try: + os.replace(CONFIG_PATH, CONFIG_PATH + ".bak") + except OSError: + pass + # Atomarer Write: erst .tmp schreiben, dann umbenennen + tmp = CONFIG_PATH + ".tmp" + with open(tmp, "w") as f: json.dump(data, f, indent=2) + os.replace(tmp, CONFIG_PATH) # ── Aggregation ───────────────────────────────────────────────