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:
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user