Feature: Abrechnungsperiode + Strompreise im Energie-Dashboard (v1.7.0)

- history.py: Tabelle period_starts — speichert kWh-Zählerstand zu Monats-/Jahresbeginn
- main.py: price_import/price_export in Config; /api/period-energy Endpoint
- Web UI: Preisfelder in Einstellungen (€/kWh Bezug + Vergütung)
- Energie-Dashboard: Cards zeigen Monat/Jahr kWh + Kosten statt All-Time-Total

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
retr0
2026-04-28 22:37:09 +02:00
parent 5972ef2c35
commit e9ca2fcc7d
4 changed files with 138 additions and 17 deletions
+35
View File
@@ -86,6 +86,8 @@ def _defaults() -> Dict[str, Any]:
"mqtt_port": 1883,
"mqtt_user": "",
"mqtt_pass": "",
"price_import": 0.30,
"price_export": 0.08,
"inverters": [],
}
@@ -114,6 +116,8 @@ def save_config():
"mqtt_port": State.mqtt_cfg.get("mqtt_port", 1883),
"mqtt_user": State.mqtt_cfg.get("mqtt_user", ""),
"mqtt_pass": State.mqtt_cfg.get("mqtt_pass", ""),
"price_import": State.mqtt_cfg.get("price_import", 0.30),
"price_export": State.mqtt_cfg.get("price_export", 0.08),
"inverters": State.inverters_cfg,
}
with open(CONFIG_PATH, "w") as f:
@@ -338,10 +342,41 @@ def api_save_config():
State.mqtt_cfg[k] = data[k]
if data.get("mqtt_pass"):
State.mqtt_cfg["mqtt_pass"] = data["mqtt_pass"]
for k in ("price_import", "price_export"):
if k in data:
State.mqtt_cfg[k] = float(data[k])
save_config()
threading.Thread(target=_restart_all, daemon=True).start()
return jsonify({"ok": True})
@app.get("/api/period-energy")
def api_period_energy():
agg = _compute_aggregates()
price_import = float(State.mqtt_cfg.get("price_import", 0.30))
price_export = float(State.mqtt_cfg.get("price_export", 0.08))
result = {"price_import": price_import, "price_export": price_export}
for period_type in ("monthly", "yearly"):
key = history.period_key(period_type)
entry = {}
for agg_id in ("grid_import_kwh", "grid_export_kwh", "total_energy_today"):
cur = agg.get(agg_id)
if cur is None:
continue
history.save_period_start_if_new(agg_id, period_type, key, cur)
val = history.get_period_consumption(agg_id, period_type, key, cur)
if val is not None:
entry[agg_id] = round(val, 2)
if "grid_import_kwh" in entry:
entry["import_cost"] = round(entry["grid_import_kwh"] * price_import, 2)
if "grid_export_kwh" in entry:
entry["export_revenue"] = round(entry["grid_export_kwh"] * price_export, 2)
result[period_type] = entry
return jsonify(result)
@app.get("/api/inverters-config")
def api_get_inverters():
with State.lock: