mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-10-29 17:21:57 +00:00
fix(genetic): allow optimization without fresh SoC (#1403)
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import math
|
||||
from typing import Annotated, Any, Optional
|
||||
|
||||
from loguru import logger
|
||||
from pydantic import AliasChoices, Field, field_validator
|
||||
|
||||
from akkudoktoreos.core.coreabc import (
|
||||
@@ -48,7 +49,11 @@ class RuntimeForecasts(GeneticParametersBaseModel):
|
||||
class ConfigOptimizationRequest(
|
||||
ConfigMixin, MeasurementMixin, PredictionMixin, GeneticParametersBaseModel
|
||||
):
|
||||
"""Supply observations while hardware, tariffs and scheduling remain in config."""
|
||||
"""Supply observations while hardware, tariffs and scheduling remain in config.
|
||||
|
||||
Explicit SoC values take precedence over fresh measurements. Without a usable
|
||||
measurement, assume 0% initial SoC for the affected device and continue.
|
||||
"""
|
||||
|
||||
soc: dict[str, Annotated[int, Field(ge=0, le=100)]] = Field(default_factory=dict)
|
||||
forecasts: RuntimeForecasts = Field(default_factory=RuntimeForecasts)
|
||||
@@ -115,9 +120,13 @@ class ConfigOptimizationRequest(
|
||||
raise ValueError("Invalid or stale SoC factor")
|
||||
return int(value * 100)
|
||||
except (ValueError, KeyError) as exc:
|
||||
raise ValueError(
|
||||
f"Fresh SoC missing for {device.device_id}; supply soc or a measurement."
|
||||
) from exc
|
||||
logger.warning(
|
||||
"No usable fresh SoC for {}; assuming 0% initial SoC for this "
|
||||
"optimization (not a measurement): {}",
|
||||
device.device_id,
|
||||
exc,
|
||||
)
|
||||
return 0
|
||||
|
||||
battery = None
|
||||
if groups["batteries"]:
|
||||
|
||||
@@ -154,7 +154,10 @@ class GeneticCommonSettings(SettingsBaseModel):
|
||||
measurement_max_age_seconds: int = Field(
|
||||
default=300,
|
||||
gt=0,
|
||||
description="Maximum age of SoC measurements for configuration-based optimization [s].",
|
||||
description=(
|
||||
"Maximum age of SoC measurements used for configuration-based optimization [s]. "
|
||||
"Without an explicit SoC or usable measurement, the initial SoC defaults to 0%."
|
||||
),
|
||||
)
|
||||
|
||||
tail_horizon_hours: int = Field(
|
||||
|
||||
@@ -2224,7 +2224,9 @@ async def fastapi_optimize_config(
|
||||
Static settings belong in configuration; query overrides are rejected.
|
||||
Forecast arrays start at local
|
||||
midnight and contain Wh per configured GENETIC slot; prices are currency/Wh.
|
||||
An empty body uses configured providers and fresh measured states of charge.
|
||||
An empty body uses configured providers. Explicit SoC values take precedence over
|
||||
fresh measured states of charge; missing usable measurements default to an assumed
|
||||
initial SoC of 0% without blocking a plan.
|
||||
The deprecated /optimize endpoint continues to run hourly GENETIC0.
|
||||
"""
|
||||
if request.query_params:
|
||||
@@ -2241,7 +2243,7 @@ async def fastapi_optimize_config(
|
||||
raise EOSProblem(
|
||||
status=503,
|
||||
title="GENETIC optimization failed",
|
||||
detail="No new solution was produced. Check configured devices, fresh SoC and forecast coverage.",
|
||||
detail="No new solution was produced. Check configured devices and forecast coverage.",
|
||||
)
|
||||
if not isinstance(solution, GeneticSolution):
|
||||
raise EOSProblem(
|
||||
|
||||
Reference in New Issue
Block a user