Files
EOS/tests/test_pvforecastimport.py
Bobby Noelte 3bb0e02aed fix: provider settings in top level field of configuration (#1161)
Configuration for some providers was given in the sub-field `provider_settings`
combining the settings of several providers. Pydantic does not understand
this very well and the configuration became cumbersome, especially in EOSdash.

All provider settings from the `provider-settings` sub-field are now lifted
to the top level field of the configuration.

The changes are automatically migrated in the configuration.

Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
2026-07-20 14:37:03 +02:00

115 lines
4.1 KiB
Python

import json
from pathlib import Path
import numpy.testing as npt
import pytest
from akkudoktoreos.core.coreabc import get_ems
from akkudoktoreos.prediction.pvforecastimport import PVForecastImport
from akkudoktoreos.utils.datetimeutil import compare_datetimes, to_datetime, to_duration
DIR_TESTDATA = Path(__file__).absolute().parent.joinpath("testdata")
FILE_TESTDATA_PVFORECASTIMPORT_1_JSON = DIR_TESTDATA.joinpath("import_input_1.json")
@pytest.fixture
def provider(sample_import_1_json, config_eos):
"""Fixture to create a PVForecastProvider instance."""
settings = {
"pvforecast": {
"provider": "PVForecastImport",
"pvforecastimport": {
"import_file_path": str(FILE_TESTDATA_PVFORECASTIMPORT_1_JSON),
"import_json": json.dumps(sample_import_1_json),
},
}
}
config_eos.merge_settings_from_dict(settings)
provider = PVForecastImport()
assert provider.enabled()
return provider
@pytest.fixture
def sample_import_1_json():
"""Fixture that returns sample forecast data report."""
with FILE_TESTDATA_PVFORECASTIMPORT_1_JSON.open("r", encoding="utf-8", newline=None) as f_res:
input_data = json.load(f_res)
return input_data
# ------------------------------------------------
# General forecast
# ------------------------------------------------
def test_singleton_instance(provider):
"""Test that PVForecastForecast behaves as a singleton."""
another_instance = PVForecastImport()
assert provider is another_instance
def test_invalid_provider(provider, config_eos):
"""Test requesting an unsupported provider."""
settings = {
"pvforecast": {
"provider": "<invalid>",
"pvforecastimport": {
"import_file_path": str(FILE_TESTDATA_PVFORECASTIMPORT_1_JSON),
},
}
}
with pytest.raises(ValueError, match="not a valid PV forecast provider"):
config_eos.merge_settings_from_dict(settings)
# ------------------------------------------------
# Import
# ------------------------------------------------
@pytest.mark.asyncio
@pytest.mark.parametrize(
"start_datetime, from_file",
[
("2024-11-10 00:00:00", True), # No DST in Germany
("2024-08-10 00:00:00", True), # DST in Germany
("2024-03-31 00:00:00", True), # DST change in Germany (23 hours/ day)
("2024-10-27 00:00:00", True), # DST change in Germany (25 hours/ day)
("2024-11-10 00:00:00", False), # No DST in Germany
("2024-08-10 00:00:00", False), # DST in Germany
("2024-03-31 00:00:00", False), # DST change in Germany (23 hours/ day)
("2024-10-27 00:00:00", False), # DST change in Germany (25 hours/ day)
],
)
async def test_import(provider, sample_import_1_json, start_datetime, from_file, config_eos):
"""Test fetching forecast from import."""
key = "pvforecast_ac_power"
ems_eos = get_ems()
ems_eos.set_start_datetime(to_datetime(start_datetime, in_timezone="Europe/Berlin"))
if from_file:
config_eos.pvforecast.pvforecastimport.import_json = None
assert config_eos.pvforecast.pvforecastimport.import_json is None
else:
config_eos.pvforecast.pvforecastimport.import_file_path = None
assert config_eos.pvforecast.pvforecastimport.import_file_path is None
await provider.delete_by_datetime(start_datetime=None, end_datetime=None)
# Call the method
await provider.update_data()
# Assert: Verify the result is as expected
assert provider.ems_start_datetime is not None
assert provider.total_hours is not None
assert compare_datetimes(provider.ems_start_datetime, ems_eos.start_datetime).equal
expected_values = sample_import_1_json[key]
result_values = await provider.key_to_array(
key=key,
start_datetime=provider.ems_start_datetime,
end_datetime=provider.ems_start_datetime + to_duration(f"{len(expected_values)} hours"),
interval=to_duration("1 hour"),
)
# Allow for some difference due to value calculation on DST change
npt.assert_allclose(result_values, expected_values, rtol=0.001)