mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-03-14 10:36:18 +00:00
feat: make home assistant add-on run optimization by default (#940)
When running as Home Assistant add-on the only viable usage is running with cyclic optimization. Make this the default to als propvide a better experience for first time users. The optimization will start with demo data, which also helps to configure Akkudoktor-EOS to the personal usage. The disabling of the automatic energy management is now an explicit mode "DISABLED". Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
# the root directory (no add-on folder as usual).
|
||||
|
||||
name: "Akkudoktor-EOS"
|
||||
version: "0.2.0.dev2603130753300674"
|
||||
version: "0.2.0.dev2603131189846912"
|
||||
slug: "eos"
|
||||
description: "Akkudoktor-EOS add-on"
|
||||
url: "https://github.com/Akkudoktor-EOS/EOS"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||
| interval | `EOS_EMS__INTERVAL` | `float` | `rw` | `300.0` | Intervall between EOS energy management runs [seconds]. |
|
||||
| mode | `EOS_EMS__MODE` | `Optional[akkudoktoreos.core.emsettings.EnergyManagementMode]` | `rw` | `None` | Energy management mode [OPTIMIZATION | PREDICTION]. |
|
||||
| mode | `EOS_EMS__MODE` | `<enum 'EnergyManagementMode'>` | `rw` | `required` | Energy management mode [DISABLED | OPTIMIZATION | PREDICTION]. |
|
||||
| startup_delay | `EOS_EMS__STARTUP_DELAY` | `float` | `rw` | `5` | Startup delay in seconds for EOS energy management runs. |
|
||||
:::
|
||||
<!-- pyml enable line-length -->
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Akkudoktor-EOS
|
||||
|
||||
**Version**: `v0.2.0.dev2603130753300674`
|
||||
**Version**: `v0.2.0.dev2603131189846912`
|
||||
|
||||
<!-- pyml disable line-length -->
|
||||
**Description**: This project provides a comprehensive solution for simulating and optimizing an energy system based on renewable energy sources. With a focus on photovoltaic (PV) systems, battery storage (batteries), load management (consumer requirements), heat pumps, electric vehicles, and consideration of electricity price data, this system enables forecasting and optimization of energy flow and costs over a specified period.
|
||||
|
||||
@@ -107,10 +107,11 @@ If no interval is configured (`None`, `null`) there will be only one energy mana
|
||||
startup.
|
||||
:::
|
||||
|
||||
The energy management can be run in two modes:
|
||||
The energy management can be run in three modes:
|
||||
|
||||
- **OPTIMIZATION**: A full optimization is done. This includes update of predictions.
|
||||
- **PREDICTION**: Only the predictions are updated.
|
||||
- **DISABLED**: No energy management is run.
|
||||
|
||||
**Example:**
|
||||
|
||||
|
||||
@@ -17,6 +17,12 @@ The `POST /optimize` endpoint interface does not regard configurations set for t
|
||||
passed to the request. You have to set the parameters even if given in the configuration.
|
||||
:::
|
||||
|
||||
:::{admonition} Warning
|
||||
:class: warning
|
||||
To prevent automatic optimization from interfering with `POST /optimize` requests, set `ems.mode`
|
||||
to `DISABLED` in the configuration.
|
||||
:::
|
||||
|
||||
## Input Payload
|
||||
|
||||
### Sample Request
|
||||
@@ -86,6 +92,12 @@ passed to the request. You have to set the parameters even if given in the confi
|
||||
"initial_soc_percentage": 54,
|
||||
"min_soc_percentage": 0
|
||||
},
|
||||
"dishwasher": {
|
||||
"device_id": "dishwasher1",
|
||||
"consumption_wh": 2000,
|
||||
"duration_h": 3,
|
||||
"time_windows": null
|
||||
},
|
||||
"temperature_forecast": [
|
||||
18.3, 17.8, 16.9, 16.2, 15.6, 15.1, 14.6, 14.2, 14.3, 14.8, 15.7, 16.7, 17.4,
|
||||
18.0, 18.6, 19.2, 19.1, 18.7, 18.5, 17.7, 16.2, 14.6, 13.6, 13.0, 12.6, 12.2,
|
||||
|
||||
16
openapi.json
16
openapi.json
@@ -8,7 +8,7 @@
|
||||
"name": "Apache 2.0",
|
||||
"url": "https://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
},
|
||||
"version": "v0.2.0.dev2603130753300674"
|
||||
"version": "v0.2.0.dev2603131189846912"
|
||||
},
|
||||
"paths": {
|
||||
"/v1/admin/cache/clear": {
|
||||
@@ -3833,15 +3833,8 @@
|
||||
]
|
||||
},
|
||||
"mode": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/EnergyManagementMode"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Energy management mode [OPTIMIZATION | PREDICTION].",
|
||||
"$ref": "#/components/schemas/EnergyManagementMode",
|
||||
"description": "Energy management mode [DISABLED | OPTIMIZATION | PREDICTION].",
|
||||
"examples": [
|
||||
"OPTIMIZATION",
|
||||
"PREDICTION"
|
||||
@@ -3855,6 +3848,7 @@
|
||||
"EnergyManagementMode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"DISABLED",
|
||||
"PREDICTION",
|
||||
"OPTIMIZATION"
|
||||
],
|
||||
@@ -5410,7 +5404,7 @@
|
||||
"examples": [
|
||||
[
|
||||
{
|
||||
"duration": "2 hours",
|
||||
"duration": "3 hours",
|
||||
"start_time": "10:00"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -23,7 +23,7 @@ from pydantic import Field, computed_field, field_validator
|
||||
|
||||
# settings
|
||||
from akkudoktoreos.adapter.adapter import AdapterCommonSettings
|
||||
from akkudoktoreos.config.configabc import SettingsBaseModel
|
||||
from akkudoktoreos.config.configabc import SettingsBaseModel, is_home_assistant_addon
|
||||
from akkudoktoreos.config.configmigrate import migrate_config_data, migrate_config_file
|
||||
from akkudoktoreos.core.cachesettings import CacheCommonSettings
|
||||
from akkudoktoreos.core.coreabc import SingletonMixin
|
||||
@@ -69,14 +69,6 @@ def get_absolute_path(
|
||||
return None
|
||||
|
||||
|
||||
def is_home_assistant_addon() -> bool:
|
||||
"""Detect Home Assistant add-on environment.
|
||||
|
||||
Home Assistant sets this environment variable automatically.
|
||||
"""
|
||||
return "HASSIO_TOKEN" in os.environ or "SUPERVISOR_TOKEN" in os.environ
|
||||
|
||||
|
||||
def default_data_folder_path() -> Path:
|
||||
"""Provide default data folder path.
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Abstract and base classes for configuration."""
|
||||
|
||||
import calendar
|
||||
import os
|
||||
from typing import Any, ClassVar, Iterator, Optional, Union
|
||||
|
||||
import numpy as np
|
||||
@@ -18,6 +19,14 @@ from akkudoktoreos.utils.datetimeutil import (
|
||||
)
|
||||
|
||||
|
||||
def is_home_assistant_addon() -> bool:
|
||||
"""Detect Home Assistant add-on environment.
|
||||
|
||||
Home Assistant sets this environment variable automatically.
|
||||
"""
|
||||
return "HASSIO_TOKEN" in os.environ or "SUPERVISOR_TOKEN" in os.environ
|
||||
|
||||
|
||||
class SettingsBaseModel(PydanticBaseModel):
|
||||
"""Base model class for all settings configurations."""
|
||||
|
||||
|
||||
@@ -154,8 +154,8 @@ class EnergyManagement(
|
||||
@classmethod
|
||||
def _run(
|
||||
cls,
|
||||
start_datetime: Optional[DateTime] = None,
|
||||
mode: Optional[EnergyManagementMode] = None,
|
||||
start_datetime: DateTime,
|
||||
mode: EnergyManagementMode,
|
||||
genetic_parameters: Optional[GeneticOptimizationParameters] = None,
|
||||
genetic_individuals: Optional[int] = None,
|
||||
genetic_seed: Optional[int] = None,
|
||||
@@ -170,14 +170,11 @@ class EnergyManagement(
|
||||
optimization depending on the selected mode or configuration.
|
||||
|
||||
Args:
|
||||
start_datetime (DateTime, optional): The starting timestamp
|
||||
of the energy management run. Defaults to the current datetime
|
||||
if not provided.
|
||||
mode (EnergyManagementMode, optional): The management mode to use. Must be one of:
|
||||
start_datetime (DateTime): The starting timestamp of the energy management run.
|
||||
mode (EnergyManagementMode): The management mode to use. Must be one of:
|
||||
- "OPTIMIZATION": Runs the optimization process.
|
||||
- "PREDICTION": Updates the forecast without optimization.
|
||||
|
||||
Defaults to the mode defined in the current configuration.
|
||||
- "DISABLED": Does not run.
|
||||
genetic_parameters (GeneticOptimizationParameters, optional): The
|
||||
parameter set for the genetic algorithm. If not provided, it will
|
||||
be constructed based on the current configuration and predictions.
|
||||
@@ -196,8 +193,10 @@ class EnergyManagement(
|
||||
None
|
||||
"""
|
||||
# Ensure there is only one optimization/ energy management run at a time
|
||||
if mode not in (None, "PREDICTION", "OPTIMIZATION"):
|
||||
if not EnergyManagementMode.is_valid(mode):
|
||||
raise ValueError(f"Unknown energy management mode {mode}.")
|
||||
if mode == EnergyManagementMode.DISABLED:
|
||||
return
|
||||
|
||||
logger.info("Starting energy management run.")
|
||||
|
||||
@@ -220,9 +219,7 @@ class EnergyManagement(
|
||||
|
||||
cls._stage = EnergyManagementStage.FORECAST_RETRIEVAL
|
||||
|
||||
if mode is None:
|
||||
mode = cls.config.ems.mode
|
||||
if mode is None or mode == "PREDICTION":
|
||||
if mode == EnergyManagementMode.PREDICTION:
|
||||
# Update the predictions
|
||||
cls.prediction.update_data(force_enable=force_enable, force_update=force_update)
|
||||
logger.info("Energy management run done (predictions updated)")
|
||||
@@ -346,6 +343,10 @@ class EnergyManagement(
|
||||
async with self._run_lock:
|
||||
loop = get_running_loop()
|
||||
# Create a partial function with parameters "baked in"
|
||||
if start_datetime is None:
|
||||
start_datetime = to_datetime()
|
||||
if mode is None:
|
||||
mode = self.config.ems.mode
|
||||
func = partial(
|
||||
EnergyManagement._run,
|
||||
start_datetime=start_datetime,
|
||||
|
||||
@@ -4,19 +4,47 @@ Kept in an extra module to avoid cyclic dependencies on package import.
|
||||
"""
|
||||
|
||||
from enum import Enum
|
||||
from typing import Optional
|
||||
from typing import Optional, Union
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
from akkudoktoreos.config.configabc import SettingsBaseModel
|
||||
from akkudoktoreos.config.configabc import SettingsBaseModel, is_home_assistant_addon
|
||||
|
||||
|
||||
class EnergyManagementMode(str, Enum):
|
||||
"""Energy management mode."""
|
||||
|
||||
DISABLED = "DISABLED"
|
||||
PREDICTION = "PREDICTION"
|
||||
OPTIMIZATION = "OPTIMIZATION"
|
||||
|
||||
@classmethod
|
||||
def is_valid(cls, mode: Union[str, "EnergyManagementMode"]) -> bool:
|
||||
"""Check if value is a valid mode."""
|
||||
try:
|
||||
cls(mode)
|
||||
return True
|
||||
except (ValueError, TypeError):
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def from_value(cls, value: str) -> Optional["EnergyManagementMode"]:
|
||||
"""Safely convert string to enum, return None if invalid."""
|
||||
try:
|
||||
return cls(value)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
class EnergyManagementCommonSettings(SettingsBaseModel):
|
||||
"""Energy Management Configuration."""
|
||||
@@ -38,10 +66,10 @@ class EnergyManagementCommonSettings(SettingsBaseModel):
|
||||
},
|
||||
)
|
||||
|
||||
mode: Optional[EnergyManagementMode] = Field(
|
||||
default=None,
|
||||
mode: EnergyManagementMode = Field(
|
||||
default_factory=ems_default_mode,
|
||||
json_schema_extra={
|
||||
"description": "Energy management mode [OPTIMIZATION | PREDICTION].",
|
||||
"description": "Energy management mode [DISABLED | OPTIMIZATION | PREDICTION].",
|
||||
"examples": ["OPTIMIZATION", "PREDICTION"],
|
||||
},
|
||||
)
|
||||
|
||||
@@ -139,7 +139,7 @@ class HomeApplianceParameters(DeviceParameters):
|
||||
"description": "List of allowed time windows. Defaults to optimization general time window.",
|
||||
"examples": [
|
||||
[
|
||||
{"start_time": "10:00", "duration": "2 hours"},
|
||||
{"start_time": "10:00", "duration": "3 hours"},
|
||||
],
|
||||
],
|
||||
},
|
||||
|
||||
@@ -727,9 +727,9 @@ def Configuration(
|
||||
# Home Assistant adapter optimization solution entities
|
||||
update_form_factory = make_config_update_list_form(eos_solution_entity_ids)
|
||||
elif config["name"].startswith("ems.mode"):
|
||||
# Energy managemnt mode
|
||||
# Energy management mode
|
||||
update_form_factory = make_config_update_value_form(
|
||||
["OPTIMIZATION", "PREDICTION", "None"]
|
||||
["OPTIMIZATION", "PREDICTION", "DISABLED"]
|
||||
)
|
||||
elif config["name"].endswith("elecpricefixed.time_windows.windows"):
|
||||
update_form_factory = make_config_update_time_windows_windows_form(
|
||||
|
||||
Reference in New Issue
Block a user