mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-07-19 08:18:50 +00:00
fix: prediction import with pydantic-typed bodies (#1152)
Some checks failed
Bump Version / Bump Version Workflow (push) Has been cancelled
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
docker-build / platform-excludes (push) Has been cancelled
docker-build / build (push) Has been cancelled
docker-build / merge (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
Run Pytest on Pull Request / test (push) Has been cancelled
Close stale pull requests/issues / Find Stale issues and PRs (push) Has been cancelled
Some checks failed
Bump Version / Bump Version Workflow (push) Has been cancelled
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
docker-build / platform-excludes (push) Has been cancelled
docker-build / build (push) Has been cancelled
docker-build / merge (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
Run Pytest on Pull Request / test (push) Has been cancelled
Close stale pull requests/issues / Find Stale issues and PRs (push) Has been cancelled
Respect pydantic model in serializing json data for import. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
This commit is contained in:
2
.env
2
.env
@@ -11,7 +11,7 @@ DOCKER_COMPOSE_DATA_DIR=${HOME}/.local/share/net.akkudoktor.eos
|
||||
# -----------------------------------------------------------------------------
|
||||
# Image / build
|
||||
# -----------------------------------------------------------------------------
|
||||
VERSION=0.3.0.dev2607150960221650
|
||||
VERSION=0.3.0.dev2607161418098328
|
||||
PYTHON_VERSION=3.13.9
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# the root directory (no add-on folder as usual).
|
||||
|
||||
name: "Akkudoktor-EOS"
|
||||
version: "0.3.0.dev2607150960221650"
|
||||
version: "0.3.0.dev2607161418098328"
|
||||
slug: "eos"
|
||||
description: "Akkudoktor-EOS add-on"
|
||||
url: "https://github.com/Akkudoktor-EOS/EOS"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Akkudoktor-EOS
|
||||
|
||||
**Version**: `v0.3.0.dev2607150960221650`
|
||||
**Version**: `v0.3.0.dev2607161418098328`
|
||||
|
||||
<!-- 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.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"name": "Apache 2.0",
|
||||
"url": "https://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
},
|
||||
"version": "v0.3.0.dev2607150960221650"
|
||||
"version": "v0.3.0.dev2607161418098328"
|
||||
},
|
||||
"paths": {
|
||||
"/v1/admin/cache/clear": {
|
||||
|
||||
@@ -9,7 +9,7 @@ from akkudoktoreos.prediction.feedintarifffixed import FeedInTariffFixedCommonSe
|
||||
from akkudoktoreos.prediction.feedintariffimport import FeedInTariffImportCommonSettings
|
||||
|
||||
|
||||
def elecprice_provider_ids() -> list[str]:
|
||||
def feedintariff_provider_ids() -> list[str]:
|
||||
"""Valid feedintariff provider ids."""
|
||||
try:
|
||||
prediction_eos = get_prediction()
|
||||
@@ -67,14 +67,14 @@ class FeedInTariffCommonSettings(SettingsBaseModel):
|
||||
@property
|
||||
def providers(self) -> list[str]:
|
||||
"""Available feed in tariff provider ids."""
|
||||
return elecprice_provider_ids()
|
||||
return feedintariff_provider_ids()
|
||||
|
||||
# Validators
|
||||
@field_validator("provider", mode="after")
|
||||
@classmethod
|
||||
def validate_provider(cls, value: Optional[str]) -> Optional[str]:
|
||||
if value is None or value in elecprice_provider_ids():
|
||||
if value is None or value in feedintariff_provider_ids():
|
||||
return value
|
||||
raise ValueError(
|
||||
f"Provider '{value}' is not a valid feed in tariff provider: {elecprice_provider_ids()}."
|
||||
f"Provider '{value}' is not a valid feed in tariff provider: {feedintariff_provider_ids()}."
|
||||
)
|
||||
|
||||
@@ -40,6 +40,7 @@ from akkudoktoreos.core.ems import ems_manage_energy
|
||||
from akkudoktoreos.core.emsettings import EnergyManagementMode
|
||||
from akkudoktoreos.core.logging import logging_track_config, read_file_log
|
||||
from akkudoktoreos.core.pydantic import (
|
||||
BaseModel,
|
||||
PydanticBaseModel,
|
||||
PydanticDateTimeData,
|
||||
PydanticDateTimeDataFrame,
|
||||
@@ -1036,7 +1037,7 @@ async def fastapi_prediction_list_get(
|
||||
|
||||
|
||||
@app.put("/v1/prediction/import/{provider_id}", tags=["prediction"])
|
||||
def fastapi_prediction_import_provider(
|
||||
async def fastapi_prediction_import_provider(
|
||||
provider_id: str = FastapiPath(..., description="Provider ID."),
|
||||
data: Optional[Union[PydanticDateTimeDataFrame, PydanticDateTimeData, dict]] = None,
|
||||
force_enable: Optional[bool] = None,
|
||||
@@ -1056,7 +1057,11 @@ def fastapi_prediction_import_provider(
|
||||
if not provider.enabled() and not force_enable:
|
||||
raise HTTPException(status_code=404, detail=f"Provider '{provider_id}' not enabled.")
|
||||
try:
|
||||
provider.import_from_json(json_str=json.dumps(data))
|
||||
if isinstance(data, BaseModel):
|
||||
json_str = data.model_dump_json()
|
||||
else:
|
||||
json_str = json.dumps(data)
|
||||
await provider.import_from_json(json_str=json_str)
|
||||
provider.update_datetime = to_datetime(in_timezone=get_config().general.timezone)
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
|
||||
@@ -170,6 +170,57 @@ class TestSystem:
|
||||
else:
|
||||
pass
|
||||
|
||||
def test_prediction_import(self, server_setup_for_class, is_system_test):
|
||||
"""Test eprediction import."""
|
||||
server = server_setup_for_class["server"]
|
||||
eos_dir = server_setup_for_class["eos_dir"]
|
||||
|
||||
# Reset config
|
||||
with FILE_TESTDATA_EOSSERVER_CONFIG_1.open("r", encoding="utf-8", newline=None) as fd:
|
||||
config = json.load(fd)
|
||||
config["elecprice"]["provider"] = "ElecPriceImport"
|
||||
result = requests.put(f"{server}/v1/config", json=config)
|
||||
assert result.status_code == HTTPStatus.OK
|
||||
|
||||
# Assure prediction is enabled
|
||||
result = requests.get(f"{server}/v1/prediction/providers?enabled=true")
|
||||
assert result.status_code == HTTPStatus.OK
|
||||
providers = result.json()
|
||||
assert "ElecPriceImport" in providers
|
||||
|
||||
# Elex price payload
|
||||
payload = {
|
||||
"start_datetime": "2026-05-27 00:00:00",
|
||||
"interval": "1 hour",
|
||||
"elecprice_marketprice_wh": [0.000234, 0.000228, 0.000231],
|
||||
}
|
||||
|
||||
result = requests.put(
|
||||
f"{server}/v1/prediction/import/ElecPriceImport",
|
||||
params={"force_enable": True},
|
||||
json=payload,
|
||||
)
|
||||
assert result.status_code == HTTPStatus.OK
|
||||
|
||||
# Import should work with any provider
|
||||
config["feedintariff"]["provider"] = "FeedInTariffImport"
|
||||
result = requests.put(f"{server}/v1/config", json=config)
|
||||
assert result.status_code == HTTPStatus.OK
|
||||
|
||||
# Feed In Tariff payload
|
||||
payload = {
|
||||
"start_datetime": "2026-05-27 00:00:00",
|
||||
"interval": "1 hour",
|
||||
"feed_in_tariff_wh": [0.000071, 0.000072, 0.000073],
|
||||
}
|
||||
|
||||
result = requests.put(
|
||||
f"{server}/v1/prediction/import/FeedInTariffImport",
|
||||
params={"force_enable": True},
|
||||
json=payload,
|
||||
)
|
||||
assert result.status_code == HTTPStatus.OK
|
||||
|
||||
def test_measurement(self, server_setup_for_class, is_system_test):
|
||||
"""Test measurement endpoints comprehensively."""
|
||||
server = server_setup_for_class["server"]
|
||||
|
||||
3
tests/testdata/eosserver_config_1.json
vendored
3
tests/testdata/eosserver_config_1.json
vendored
@@ -3,6 +3,9 @@
|
||||
"charges_kwh": 0.21,
|
||||
"provider": "ElecPriceImport"
|
||||
},
|
||||
"feedintariff": {
|
||||
"provider": "FeedInTariffFixed"
|
||||
},
|
||||
"general": {
|
||||
"latitude": 52.5,
|
||||
"longitude": 13.4
|
||||
|
||||
8
uv.lock
generated
8
uv.lock
generated
@@ -116,7 +116,7 @@ requires-dist = [
|
||||
{ name = "pytest-asyncio", marker = "extra == 'dev'", specifier = "==1.4.0" },
|
||||
{ name = "pytest-cov", marker = "extra == 'dev'", specifier = "==7.1.0" },
|
||||
{ name = "pytest-xprocess", marker = "extra == 'dev'", specifier = "==1.0.2" },
|
||||
{ name = "python-fasthtml", specifier = "==0.14.5" },
|
||||
{ name = "python-fasthtml", specifier = "==0.14.6" },
|
||||
{ name = "requests", specifier = "==2.34.2" },
|
||||
{ name = "rich-toolkit", specifier = "==0.20.3" },
|
||||
{ name = "scipy", specifier = "==1.17.1" },
|
||||
@@ -2697,7 +2697,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "python-fasthtml"
|
||||
version = "0.14.5"
|
||||
version = "0.14.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "beautifulsoup4" },
|
||||
@@ -2711,9 +2711,9 @@ dependencies = [
|
||||
{ name = "starlette" },
|
||||
{ name = "uvicorn", extra = ["standard"] },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/be/9b/e442133c5d950d9ccc0a879357a3c108e1dcfd80a19bd601459a615c1a7e/python_fasthtml-0.14.5.tar.gz", hash = "sha256:d0181c36415f9bbe242e1d05de1fb5279a14aa9c605c244e76ae95a32650eda4", size = 76817, upload-time = "2026-07-09T05:46:10.028Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5a/db/1efed9c205c9f65a1e9715f91aff1510fdc42e41f8c032718274969b35a7/python_fasthtml-0.14.6.tar.gz", hash = "sha256:11b535e752b4f79e8da7eb6d55928d2ced0ed7a085619ac89a6e943a76915773", size = 77102, upload-time = "2026-07-11T04:03:42.889Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/63/5685ed7eff6b581bcfd0db4e239c8d07d0e1e59c016b409a1c01c10aab64/python_fasthtml-0.14.5-py3-none-any.whl", hash = "sha256:e5ce3cc43af056ac5d48b1cdcb9346111fdb8a21fa0fcf788d2490c8ea12dc9f", size = 80441, upload-time = "2026-07-09T05:46:08.427Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/d6/70783f684b6c367466c4288005e0f95cdf9ffdd1d8f397fad921f9567d10/python_fasthtml-0.14.6-py3-none-any.whl", hash = "sha256:38a93cfb87911ae34aaa088e3b53784a5ed72c575bc9656df7599d82428ab41c", size = 80779, upload-time = "2026-07-11T04:03:41.222Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Reference in New Issue
Block a user