EOS/tests/test_pvforecastimport.py
Dominique Lasserre be26457563 Nested config, devices registry
* All config now nested.
    - Use default config from model field default values. If providers
      should be enabled by default, non-empty default config file could
      be provided again.
    - Environment variable support with EOS_ prefix and __ between levels,
      e.g. EOS_SERVER__EOS_SERVER_PORT=8503 where all values are case
      insensitive.
      For more information see:
      https://docs.pydantic.dev/latest/concepts/pydantic_settings/#parsing-environment-variable-values
    - Use devices as registry for configured devices. DeviceBase as base
      class with for now just initializion support (in the future expand
      to operations during optimization).
    - Strip down ConfigEOS to the only configuration instance. Reload
      from file or reset to defaults is possible.

 * Fix multi-initialization of derived SingletonMixin classes.
2025-01-24 20:05:48 +01:00

118 lines
4.4 KiB
Python

import json
from pathlib import Path
import pytest
from akkudoktoreos.core.ems import get_ems
from akkudoktoreos.prediction.pvforecastimport import PVForecastImport
from akkudoktoreos.utils.datetimeutil import compare_datetimes, to_datetime
DIR_TESTDATA = Path(__file__).absolute().parent.joinpath("testdata")
FILE_TESTDATA_PVFORECASTIMPORT_1_JSON = DIR_TESTDATA.joinpath("import_input_1.json")
@pytest.fixture
def pvforecast_provider(sample_import_1_json, config_eos):
"""Fixture to create a PVForecastProvider instance."""
settings = {
"pvforecast": {
"pvforecast_provider": "PVForecastImport",
"provider_settings": {
"pvforecastimport_file_path": str(FILE_TESTDATA_PVFORECASTIMPORT_1_JSON),
"pvforecastimport_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 open(FILE_TESTDATA_PVFORECASTIMPORT_1_JSON, "r") as f_res:
input_data = json.load(f_res)
return input_data
# ------------------------------------------------
# General forecast
# ------------------------------------------------
def test_singleton_instance(pvforecast_provider):
"""Test that PVForecastForecast behaves as a singleton."""
another_instance = PVForecastImport()
assert pvforecast_provider is another_instance
def test_invalid_provider(pvforecast_provider, config_eos):
"""Test requesting an unsupported pvforecast_provider."""
settings = {
"pvforecast": {
"pvforecast_provider": "<invalid>",
"provider_settings": {
"pvforecastimport_file_path": str(FILE_TESTDATA_PVFORECASTIMPORT_1_JSON),
},
}
}
config_eos.merge_settings_from_dict(settings)
assert not pvforecast_provider.enabled()
# ------------------------------------------------
# Import
# ------------------------------------------------
@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)
],
)
def test_import(pvforecast_provider, sample_import_1_json, start_datetime, from_file, config_eos):
"""Test fetching forecast from import."""
ems_eos = get_ems()
ems_eos.set_start_datetime(to_datetime(start_datetime, in_timezone="Europe/Berlin"))
if from_file:
config_eos.pvforecast.provider_settings.pvforecastimport_json = None
assert config_eos.pvforecast.provider_settings.pvforecastimport_json is None
else:
config_eos.pvforecast.provider_settings.pvforecastimport_file_path = None
assert config_eos.pvforecast.provider_settings.pvforecastimport_file_path is None
pvforecast_provider.clear()
# Call the method
pvforecast_provider.update_data()
# Assert: Verify the result is as expected
assert pvforecast_provider.start_datetime is not None
assert pvforecast_provider.total_hours is not None
assert compare_datetimes(pvforecast_provider.start_datetime, ems_eos.start_datetime).equal
values = sample_import_1_json["pvforecast_ac_power"]
value_datetime_mapping = pvforecast_provider.import_datetimes(
ems_eos.start_datetime, len(values)
)
for i, mapping in enumerate(value_datetime_mapping):
assert i < len(pvforecast_provider.records)
expected_datetime, expected_value_index = mapping
expected_value = values[expected_value_index]
result_datetime = pvforecast_provider.records[i].date_time
result_value = pvforecast_provider.records[i]["pvforecast_ac_power"]
# print(f"{i}: Expected: {expected_datetime}:{expected_value}")
# print(f"{i}: Result: {result_datetime}:{result_value}")
assert compare_datetimes(result_datetime, expected_datetime).equal
assert result_value == expected_value