Files
Enelix-EMS/services/netplan-v4/acceptance/forecast-src/soc_diagnostics.py
T

67 lines
2.5 KiB
Python

from influxdb_client import Point, WritePrecision
DT_H = 5.0 / 60.0
def _f(config, key, default):
try:
return float(config.get(key, default) or default)
except Exception:
return float(default)
def battery_soc_points(data_obj, forecast_var, pv_dict, load_dict, grid_dict):
config = data_obj["config"]
aid = str(config["anlagen_id"])
cap_kwh = _f(config, "batt_capacity_kwh", 0.0)
if cap_kwh <= 0 or not grid_dict:
return []
min_soc = _f(config, "batt_min_soc", _f(config, "batt_min_soc_percent", 0.0))
max_soc = _f(config, "batt_max_soc", _f(config, "batt_max_soc_percent", 100.0))
charge_eff = max(0.01, min(1.0, _f(config, "batt_charge_efficiency", 0.95)))
discharge_eff = max(0.01, min(1.0, _f(config, "batt_discharge_efficiency", 0.95)))
start_soc_value = data_obj.get("current_soc_perc")
if start_soc_value is None or start_soc_value == "":
start_soc_value = config.get("batt_soc_percent", 50.0)
start_soc = float(start_soc_value)
start_soc = max(min_soc, min(max_soc, start_soc))
min_kwh = cap_kwh * min_soc / 100.0
max_kwh = cap_kwh * max_soc / 100.0
soc_kwh = max(min_kwh, min(max_kwh, cap_kwh * start_soc / 100.0))
planned_battery = (
data_obj.get("battery_plans", {})
.get(int(forecast_var), {})
.get("battery", {})
)
points = []
for t in data_obj["df_fut"].index:
if t not in grid_dict:
continue
if t in planned_battery:
battery_target_w = float(planned_battery[t]) # positiv = laden
else:
residual_w = float(load_dict.get(t, 0.0)) - float(pv_dict.get(t, 0.0))
grid_w = float(grid_dict.get(t, 0.0))
battery_target_w = grid_w - residual_w
if battery_target_w > 0:
soc_kwh += battery_target_w * DT_H / 1000.0 * charge_eff
elif battery_target_w < 0:
soc_kwh += battery_target_w * DT_H / 1000.0 / discharge_eff
soc_kwh = max(min_kwh, min(max_kwh, soc_kwh))
soc_percent = max(0.0, min(100.0, soc_kwh / cap_kwh * 100.0))
points.append(
Point("forecast_diagnostics")
.tag("anlagen_id", aid)
.tag("data_type", "battery_soc_simulation")
.tag("forecast_var", f"prog_var_{forecast_var}")
.field("soc_percent", float(soc_percent))
.time(t.to_pydatetime() if hasattr(t, "to_pydatetime") else t, WritePrecision.S)
)
return points