Feature: Konfig-Export/Import im Web UI (Einstellungen-Tab)

- GET /api/export-config → JSON-Download mit allen Geräten + MQTT (ohne Passwort)
- POST /api/import-config → Validierung + Übernahme + automatischer Neustart
- Einstellungen-Tab: Exportieren-Button + Importieren-Dateiauswahl
- btn-secondary CSS-Klasse hinzugefügt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
retr0
2026-04-27 13:06:54 +02:00
parent fe1bdb057d
commit 6ae2cbf2b2
2 changed files with 99 additions and 0 deletions
+53
View File
@@ -355,6 +355,59 @@ def api_get_models():
def api_new_id():
return jsonify({"id": uuid.uuid4().hex[:8]})
@app.get("/api/export-config")
def api_export_config():
with State.lock:
data = {
"shinebridge_export": True,
"version": 1,
"exported_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
"mqtt": {
"broker": State.mqtt_cfg.get("mqtt_broker", ""),
"port": State.mqtt_cfg.get("mqtt_port", 1883),
"user": State.mqtt_cfg.get("mqtt_user", ""),
},
"inverters": State.inverters_cfg,
}
from flask import Response
filename = f"shinebridge-config-{time.strftime('%Y%m%d-%H%M%S')}.json"
return Response(
json.dumps(data, indent=2, ensure_ascii=False),
mimetype="application/json",
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
)
@app.post("/api/import-config")
def api_import_config():
data = request.get_json(force=True) or {}
if not data.get("shinebridge_export"):
return jsonify({"error": "Keine gültige ShineBridge-Export-Datei"}), 400
inverters = data.get("inverters", [])
if not isinstance(inverters, list):
return jsonify({"error": "inverters ungültig"}), 400
for inv in inverters:
if not inv.get("modbus_ip"):
return jsonify({"error": f"modbus_ip fehlt in Gerät {inv.get('name', '?')}"}), 400
if inv.get("inverter_model") not in INVERTERS:
return jsonify({"error": f"Unbekanntes Modell: {inv.get('inverter_model')}"}), 400
with State.lock:
if mqtt := data.get("mqtt"):
if mqtt.get("broker"):
State.mqtt_cfg["mqtt_broker"] = mqtt["broker"]
if mqtt.get("port"):
State.mqtt_cfg["mqtt_port"] = int(mqtt["port"])
if mqtt.get("user"):
State.mqtt_cfg["mqtt_user"] = mqtt["user"]
State.inverters_cfg = inverters
save_config()
threading.Thread(target=_restart_all, daemon=True).start()
return jsonify({"ok": True, "inverters": len(inverters)})
@app.get("/")
def index():
return send_from_directory(WEB_DIR, "index.html")