Files
EOS/src/akkudoktoreos/core/emsettings.py
T

91 lines
2.7 KiB
Python
Raw Normal View History

2025-02-12 21:35:51 +01:00
"""Settings for energy management.
Kept in an extra module to avoid cyclic dependencies on package import.
"""
from enum import StrEnum
from typing import Optional
2025-02-12 21:35:51 +01:00
from pydantic import Field, computed_field, field_validator
2025-02-12 21:35:51 +01:00
from akkudoktoreos.config.configabc import SettingsBaseModel, is_home_assistant_addon
2025-02-12 21:35:51 +01:00
class EnergyManagementMode(StrEnum):
2025-10-28 02:50:31 +01:00
"""Energy management mode."""
DISABLED = "DISABLED"
2025-10-28 02:50:31 +01:00
PREDICTION = "PREDICTION"
OPTIMIZATION = "OPTIMIZATION"
def ems_default_mode() -> EnergyManagementMode:
"""Provide default EMS mode.
Returns OPTIMIZATION when running under Home Assistant, else DISABLED.
"""
if is_home_assistant_addon():
return EnergyManagementMode.OPTIMIZATION
return EnergyManagementMode.DISABLED
2025-10-28 02:50:31 +01:00
2025-02-12 21:35:51 +01:00
class EnergyManagementCommonSettings(SettingsBaseModel):
"""Energy Management Configuration."""
startup_delay: float = Field(
default=5,
ge=1,
json_schema_extra={
"description": "Startup delay in seconds for EOS energy management runs."
},
2025-02-12 21:35:51 +01:00
)
interval: float = Field(
default=300.0,
ge=60.0,
json_schema_extra={
"description": "Intervall between EOS energy management runs [seconds].",
"examples": ["300"],
},
2025-02-12 21:35:51 +01:00
)
2025-10-28 02:50:31 +01:00
mode: EnergyManagementMode = Field(
default_factory=ems_default_mode,
json_schema_extra={
"description": (
f"Energy management mode "
f"[{' | '.join(mode.value for mode in EnergyManagementMode)}]. "
f"Defaults to {ems_default_mode()}."
),
"examples": ["OPTIMIZATION"],
},
2025-10-28 02:50:31 +01:00
)
notify_url: Optional[str] = Field(
default=None,
json_schema_extra={
"description": (
"URL that receives an HTTP POST with a small JSON event after every "
"completed optimization, so a client can fetch the new solution right "
"away instead of polling for it. None = off."
),
"examples": [None, "http://127.0.0.1:8080/api/eos/solution-ready"],
},
)
@field_validator("notify_url")
@classmethod
def _validate_notify_url(cls, value: Optional[str]) -> Optional[str]:
if value is None or value.strip() == "":
return None
value = value.strip()
if not value.startswith(("http://", "https://")):
raise ValueError("notify_url must be an http:// or https:// URL")
return value
@computed_field # type: ignore[prop-decorator]
@property
def modes(self) -> list[str]:
"""Available energy management modes."""
return [mode.value for mode in EnergyManagementMode]