mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-03-09 08:06:17 +00:00
fix: prevent exception when load prediction data is missing (#925)
Some checks failed
Bump Version / Bump Version Workflow (push) Has been cancelled
docker-build / platform-excludes (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
Run Pytest on Pull Request / test (push) Has been cancelled
docker-build / build (push) Has been cancelled
docker-build / merge (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
docker-build / platform-excludes (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
Run Pytest on Pull Request / test (push) Has been cancelled
docker-build / build (push) Has been cancelled
docker-build / merge (push) Has been cancelled
Close stale pull requests/issues / Find Stale issues and PRs (push) Has been cancelled
Validate solution prediction data before processing. If required prediction data is missing, the prediction is skipped instead of raising an exception. Introduce a new configuration file saving policy to improve loading robustness: - Exclude computed fields - Exclude fields set to their default values - Exclude fields with value None - Use field aliases - Recursively remove empty dictionaries and lists - Ensure general.version is always present and correctly set When loading older configuration files, computed fields are now stripped before migration. This further improves backward compatibility and loading robustness. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
This commit is contained in:
99
tests/test_configfile.py
Normal file
99
tests/test_configfile.py
Normal file
@@ -0,0 +1,99 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from akkudoktoreos.config.config import ConfigEOS, GeneralSettings
|
||||
|
||||
|
||||
class TestConfigEOSToConfigFile:
|
||||
|
||||
def test_to_config_file_writes_file(self, config_eos):
|
||||
config_path = config_eos.general.config_file_path
|
||||
|
||||
# Remove file to test writing
|
||||
config_path.unlink(missing_ok=True)
|
||||
|
||||
config_eos.to_config_file()
|
||||
|
||||
assert config_path.exists()
|
||||
assert config_path.read_text().strip().startswith("{")
|
||||
|
||||
def test_to_config_file_excludes_computed_fields(self, config_eos):
|
||||
config_path = config_eos.general.config_file_path
|
||||
|
||||
config_eos.to_config_file()
|
||||
data = json.loads(config_path.read_text())
|
||||
|
||||
assert "timezone" not in data["general"]
|
||||
assert "data_output_path" not in data["general"]
|
||||
assert "config_folder_path" not in data["general"]
|
||||
assert "config_file_path" not in data["general"]
|
||||
|
||||
def test_to_config_file_excludes_defaults(self, config_eos):
|
||||
"""Ensure fields with default values are excluded when saving config."""
|
||||
|
||||
# Pick fields that have defaults
|
||||
default_latitude = GeneralSettings.model_fields["latitude"].default
|
||||
default_longitude = GeneralSettings.model_fields["longitude"].default
|
||||
|
||||
# Ensure fields are at default values
|
||||
config_eos.general.latitude = default_latitude
|
||||
config_eos.general.longitude = default_longitude
|
||||
|
||||
# Save the config using the correct path managed by config_eos
|
||||
config_eos.to_config_file()
|
||||
|
||||
# Read back JSON from the correct path
|
||||
config_file_path = config_eos.general.config_file_path
|
||||
content = json.loads(config_file_path.read_text(encoding="utf-8"))
|
||||
|
||||
# Default fields should not appear
|
||||
assert "latitude" not in content["general"]
|
||||
assert "longitude" not in content["general"]
|
||||
|
||||
# Non-default value should appear
|
||||
config_eos.general.latitude = 48.0
|
||||
config_eos.to_config_file()
|
||||
content = json.loads(config_file_path.read_text(encoding="utf-8"))
|
||||
assert content["general"]["latitude"] == 48.0
|
||||
|
||||
def test_to_config_file_excludes_none_fields(self, config_eos):
|
||||
config_eos.general.latitude = None
|
||||
|
||||
config_path = config_eos.general.config_file_path
|
||||
config_eos.to_config_file()
|
||||
|
||||
data = json.loads(config_path.read_text())
|
||||
|
||||
assert "latitude" not in data["general"]
|
||||
|
||||
def test_to_config_file_includes_version(tmp_path, config_eos):
|
||||
"""Ensure general.version is always included."""
|
||||
# Save config
|
||||
config_eos.to_config_file()
|
||||
|
||||
# Read back JSON
|
||||
config_file_path = config_eos.general.config_file_path
|
||||
content = json.loads(config_file_path.read_text(encoding="utf-8"))
|
||||
|
||||
# Assert 'version' is included even if default
|
||||
assert content["general"]["version"] == config_eos.general.version
|
||||
|
||||
def test_to_config_file_roundtrip(self, config_eos):
|
||||
config_eos.merge_settings_from_dict(
|
||||
{
|
||||
"general": {"latitude": 48.0},
|
||||
"server": {"port": 9000},
|
||||
}
|
||||
)
|
||||
|
||||
config_path = config_eos.general.config_file_path
|
||||
config_eos.to_config_file()
|
||||
|
||||
raw_data = json.loads(config_path.read_text())
|
||||
reloaded = ConfigEOS.model_validate(raw_data)
|
||||
|
||||
assert reloaded.general.latitude == 48.0
|
||||
assert reloaded.server.port == 9000
|
||||
@@ -22,6 +22,10 @@ MIGRATION_PAIRS = [
|
||||
DIR_TESTDATA / "eos_config_andreas_0_1_0.json",
|
||||
DIR_TESTDATA / "eos_config_andreas_now.json",
|
||||
),
|
||||
(
|
||||
DIR_TESTDATA / "eos_config_unstripped.json",
|
||||
DIR_TESTDATA / "eos_config_stripped.json",
|
||||
),
|
||||
# Add more pairs here:
|
||||
# (DIR_TESTDATA / "old_config_X.json", DIR_TESTDATA / "expected_config_X.json"),
|
||||
]
|
||||
@@ -124,16 +128,18 @@ class TestConfigMigration:
|
||||
new_model = SettingsEOSDefaults(**migrated_data)
|
||||
assert isinstance(new_model, SettingsEOSDefaults)
|
||||
|
||||
def test_migrate_config_file_already_current(self, tmp_path: Path):
|
||||
def test_migrate_config_file_already_current(self, tmp_config_file: Path):
|
||||
"""Test that a current config file returns True immediately."""
|
||||
config_path = tmp_path / "EOS_current.json"
|
||||
default = SettingsEOSDefaults()
|
||||
with config_path.open("w", encoding="utf-8") as f:
|
||||
f.write(default.model_dump_json(indent=4))
|
||||
backup_file = tmp_config_file.with_suffix(".bak")
|
||||
|
||||
backup_file = config_path.with_suffix(".bak")
|
||||
# Run migration
|
||||
result = configmigrate.migrate_config_file(tmp_config_file, backup_file)
|
||||
assert result is True, "Migration should succeed even from invalid version."
|
||||
|
||||
result = configmigrate.migrate_config_file(config_path, backup_file)
|
||||
backup_file.unlink()
|
||||
assert not backup_file.exists()
|
||||
|
||||
result = configmigrate.migrate_config_file(tmp_config_file, backup_file)
|
||||
assert result is True
|
||||
assert not backup_file.exists(), "No backup should be made if config is already current."
|
||||
|
||||
|
||||
175
tests/testdata/eos_config_andreas_now.json
vendored
175
tests/testdata/eos_config_andreas_now.json
vendored
@@ -1,98 +1,83 @@
|
||||
{
|
||||
"general": {
|
||||
"data_folder_path": "__ANY__",
|
||||
"data_output_subpath": "output",
|
||||
"latitude": 52.5,
|
||||
"longitude": 13.4
|
||||
},
|
||||
"cache": {
|
||||
"subpath": "cache",
|
||||
"cleanup_interval": 300.0
|
||||
},
|
||||
"ems": {
|
||||
"startup_delay": 5.0,
|
||||
"interval": 300.0
|
||||
},
|
||||
"logging": {
|
||||
"console_level": "INFO"
|
||||
},
|
||||
"devices": {
|
||||
"batteries": [
|
||||
{
|
||||
"device_id": "pv_akku",
|
||||
"capacity_wh": 30000,
|
||||
"charging_efficiency": 0.88,
|
||||
"discharging_efficiency": 0.88,
|
||||
"max_charge_power_w": 5000,
|
||||
"min_soc_percentage": 0,
|
||||
"max_soc_percentage": 100
|
||||
}
|
||||
],
|
||||
"electric_vehicles": [
|
||||
{
|
||||
"charge_rates": [0.0, 0.375, 0.5, 0.625, 0.75, 0.875, 1.0]
|
||||
}
|
||||
],
|
||||
"inverters": [],
|
||||
"home_appliances": []
|
||||
},
|
||||
"measurement": {
|
||||
"load_emr_keys": ["Household"]
|
||||
},
|
||||
"optimization": {
|
||||
"horizon_hours": 48,
|
||||
"genetic": {
|
||||
"penalties": {
|
||||
"ev_soc_miss": 10
|
||||
}
|
||||
"general": {
|
||||
"version": "__ANY__",
|
||||
"data_output_subpath": "output",
|
||||
"latitude": 52.5,
|
||||
"longitude": 13.4
|
||||
},
|
||||
"cache": {
|
||||
"subpath": "cache"
|
||||
},
|
||||
"logging": {
|
||||
"console_level": "INFO"
|
||||
},
|
||||
"devices": {
|
||||
"batteries": [
|
||||
{
|
||||
"device_id": "pv_akku",
|
||||
"capacity_wh": 30000
|
||||
}
|
||||
],
|
||||
"electric_vehicles": [
|
||||
{
|
||||
"charge_rates": [
|
||||
0.0,
|
||||
0.375,
|
||||
0.5,
|
||||
0.625,
|
||||
0.75,
|
||||
0.875,
|
||||
1.0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"measurement": {
|
||||
"load_emr_keys": [
|
||||
"Household"
|
||||
]
|
||||
},
|
||||
"optimization": {
|
||||
"horizon_hours": 48
|
||||
},
|
||||
"elecprice": {
|
||||
"provider": "ElecPriceAkkudoktor",
|
||||
"charges_kwh": 0.21
|
||||
},
|
||||
"load": {
|
||||
"loadakkudoktor": {
|
||||
"loadakkudoktor_year_energy_kwh": 13000.0
|
||||
}
|
||||
},
|
||||
"pvforecast": {
|
||||
"provider": "PVForecastAkkudoktor",
|
||||
"planes": [
|
||||
{
|
||||
"surface_tilt": 87.907,
|
||||
"surface_azimuth": 175.0,
|
||||
"userhorizon": [
|
||||
28.0,
|
||||
34.0,
|
||||
32.0,
|
||||
60.0
|
||||
],
|
||||
"peakpower": 13.11,
|
||||
"loss": 18.6,
|
||||
"trackingtype": 0,
|
||||
"albedo": 0.25,
|
||||
"inverter_paco": 15000,
|
||||
"modules_per_string": 20,
|
||||
"strings_per_inverter": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
"weather": {
|
||||
"provider": "WeatherImport"
|
||||
},
|
||||
"server": {
|
||||
"host": "0.0.0.0",
|
||||
"verbose": true,
|
||||
"eosdash_host": "0.0.0.0",
|
||||
"eosdash_port": 8504
|
||||
}
|
||||
},
|
||||
"prediction": {
|
||||
"hours": 48,
|
||||
"historic_hours": 48
|
||||
},
|
||||
"elecprice": {
|
||||
"provider": "ElecPriceAkkudoktor",
|
||||
"charges_kwh": 0.21
|
||||
},
|
||||
"load": {
|
||||
"loadakkudoktor": {
|
||||
"loadakkudoktor_year_energy_kwh": 13000
|
||||
}
|
||||
},
|
||||
"pvforecast": {
|
||||
"provider": "PVForecastAkkudoktor",
|
||||
"planes": [
|
||||
{
|
||||
"surface_tilt": 87.907,
|
||||
"surface_azimuth": 175.0,
|
||||
"userhorizon": [28.0, 34.0, 32.0, 60.0],
|
||||
"peakpower": 13.110,
|
||||
"pvtechchoice": "crystSi",
|
||||
"mountingplace": "free",
|
||||
"loss": 18.6,
|
||||
"trackingtype": 0,
|
||||
"optimal_surface_tilt": false,
|
||||
"optimalangles": false,
|
||||
"albedo": 0.25,
|
||||
"module_model": null,
|
||||
"inverter_model": null,
|
||||
"inverter_paco": 15000,
|
||||
"modules_per_string": 20,
|
||||
"strings_per_inverter": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
"weather": {
|
||||
"provider": "WeatherImport"
|
||||
},
|
||||
"server": {
|
||||
"host": "0.0.0.0",
|
||||
"port": 8503,
|
||||
"verbose": true,
|
||||
"startup_eosdash": true,
|
||||
"eosdash_host": "0.0.0.0",
|
||||
"eosdash_port": 8504
|
||||
},
|
||||
"utils": {}
|
||||
}
|
||||
|
||||
45
tests/testdata/eos_config_minimal_now.json
vendored
45
tests/testdata/eos_config_minimal_now.json
vendored
@@ -1,29 +1,20 @@
|
||||
{
|
||||
"elecprice": {
|
||||
"charges_kwh": 0.21,
|
||||
"provider": "ElecPriceImport"
|
||||
},
|
||||
"prediction": {
|
||||
"historic_hours": 48,
|
||||
"hours": 48
|
||||
},
|
||||
"optimization": {
|
||||
"horizon_hours": 48,
|
||||
"algorithm": "GENETIC",
|
||||
"genetic": {
|
||||
"individuals": 300,
|
||||
"generations": 400
|
||||
"general": {
|
||||
"version": "__ANY__",
|
||||
"data_output_subpath": "output",
|
||||
"latitude": 52.5,
|
||||
"longitude": 13.4
|
||||
},
|
||||
"optimization": {
|
||||
"horizon_hours": 48
|
||||
},
|
||||
"elecprice": {
|
||||
"provider": "ElecPriceImport",
|
||||
"charges_kwh": 0.21
|
||||
},
|
||||
"server": {
|
||||
"host": "0.0.0.0",
|
||||
"eosdash_host": "0.0.0.0",
|
||||
"eosdash_port": 8504
|
||||
}
|
||||
},
|
||||
"general": {
|
||||
"latitude": 52.5,
|
||||
"longitude": 13.4
|
||||
},
|
||||
"server": {
|
||||
"startup_eosdash": true,
|
||||
"host": "0.0.0.0",
|
||||
"port": 8503,
|
||||
"eosdash_host": "0.0.0.0",
|
||||
"eosdash_port": 8504
|
||||
}
|
||||
}
|
||||
}
|
||||
134
tests/testdata/eos_config_stripped.json
vendored
Normal file
134
tests/testdata/eos_config_stripped.json
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"general": {
|
||||
"version": "__ANY__",
|
||||
"data_output_subpath": "output"
|
||||
},
|
||||
"cache": {
|
||||
"subpath": "cache"
|
||||
},
|
||||
"ems": {
|
||||
"mode": "OPTIMIZATION"
|
||||
},
|
||||
"devices": {
|
||||
"batteries": [
|
||||
{
|
||||
"device_id": "battery1"
|
||||
}
|
||||
],
|
||||
"max_batteries": 1,
|
||||
"electric_vehicles": [
|
||||
{
|
||||
"device_id": "ev11",
|
||||
"capacity_wh": 50000,
|
||||
"min_soc_percentage": 70
|
||||
}
|
||||
],
|
||||
"max_electric_vehicles": 1,
|
||||
"inverters": [
|
||||
{
|
||||
"device_id": "inverter1",
|
||||
"max_power_w": 10000.0,
|
||||
"battery_id": "battery1"
|
||||
}
|
||||
],
|
||||
"max_inverters": 1,
|
||||
"home_appliances": [
|
||||
{
|
||||
"device_id": "dishwasher1",
|
||||
"consumption_wh": 2000,
|
||||
"duration_h": 3,
|
||||
"time_windows": {
|
||||
"windows": [
|
||||
{
|
||||
"start_time": "08:00:00.000000 Europe/Berlin",
|
||||
"duration": "5 hours"
|
||||
},
|
||||
{
|
||||
"start_time": "15:00:00.000000 Europe/Berlin",
|
||||
"duration": "3 hours"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"max_home_appliances": 1
|
||||
},
|
||||
"elecprice": {
|
||||
"provider": "ElecPriceAkkudoktor"
|
||||
},
|
||||
"feedintariff": {
|
||||
"provider": "FeedInTariffFixed",
|
||||
"provider_settings": {
|
||||
"FeedInTariffFixed": {
|
||||
"feed_in_tariff_kwh": 0.078
|
||||
}
|
||||
}
|
||||
},
|
||||
"load": {
|
||||
"provider": "LoadAkkudoktorAdjusted",
|
||||
"loadakkudoktor": {
|
||||
"loadakkudoktor_year_energy_kwh": 3000.0
|
||||
}
|
||||
},
|
||||
"pvforecast": {
|
||||
"provider": "PVForecastAkkudoktor",
|
||||
"planes": [
|
||||
{
|
||||
"surface_tilt": 7.0,
|
||||
"surface_azimuth": 170.0,
|
||||
"userhorizon": [
|
||||
20.0,
|
||||
27.0,
|
||||
22.0,
|
||||
20.0
|
||||
],
|
||||
"peakpower": 5.0,
|
||||
"inverter_paco": 10000
|
||||
},
|
||||
{
|
||||
"surface_tilt": 7.0,
|
||||
"surface_azimuth": 90.0,
|
||||
"userhorizon": [
|
||||
30.0,
|
||||
30.0,
|
||||
30.0,
|
||||
50.0
|
||||
],
|
||||
"peakpower": 4.8,
|
||||
"inverter_paco": 10000
|
||||
},
|
||||
{
|
||||
"surface_tilt": 60.0,
|
||||
"surface_azimuth": 140.0,
|
||||
"userhorizon": [
|
||||
60.0,
|
||||
30.0,
|
||||
0.0,
|
||||
30.0
|
||||
],
|
||||
"peakpower": 1.4,
|
||||
"inverter_paco": 2000
|
||||
},
|
||||
{
|
||||
"surface_tilt": 45.0,
|
||||
"surface_azimuth": 185.0,
|
||||
"userhorizon": [
|
||||
45.0,
|
||||
25.0,
|
||||
30.0,
|
||||
60.0
|
||||
],
|
||||
"peakpower": 1.6,
|
||||
"inverter_paco": 1400
|
||||
}
|
||||
],
|
||||
"max_planes": 4
|
||||
},
|
||||
"weather": {
|
||||
"provider": "BrightSky"
|
||||
},
|
||||
"server": {
|
||||
"eosdash_host": "127.0.0.1",
|
||||
"eosdash_port": 8504
|
||||
}
|
||||
}
|
||||
596
tests/testdata/eos_config_unstripped.json
vendored
Normal file
596
tests/testdata/eos_config_unstripped.json
vendored
Normal file
@@ -0,0 +1,596 @@
|
||||
{
|
||||
"general": {
|
||||
"version": "0.2.0.dev2603031877440961",
|
||||
"data_folder_path": "/home/bobby/.local/share/net.akkudoktor.eos",
|
||||
"data_output_subpath": "output",
|
||||
"latitude": 52.52,
|
||||
"longitude": 13.405,
|
||||
"timezone": "Europe/Berlin",
|
||||
"data_output_path": "/home/bobby/.local/share/net.akkudoktor.eos/output",
|
||||
"config_folder_path": "/home/bobby/.config/net.akkudoktor.eos",
|
||||
"config_file_path": "/home/bobby/.config/net.akkudoktor.eos/EOS.config.json"
|
||||
},
|
||||
"cache": {
|
||||
"subpath": "cache",
|
||||
"cleanup_interval": 300
|
||||
},
|
||||
"database": {
|
||||
"provider": null,
|
||||
"compression_level": 9,
|
||||
"initial_load_window_h": null,
|
||||
"keep_duration_h": null,
|
||||
"autosave_interval_sec": 10,
|
||||
"compaction_interval_sec": 604800,
|
||||
"batch_size": 100,
|
||||
"providers": [
|
||||
"LMDB",
|
||||
"SQLite"
|
||||
]
|
||||
},
|
||||
"ems": {
|
||||
"startup_delay": 5,
|
||||
"interval": 300,
|
||||
"mode": "OPTIMIZATION"
|
||||
},
|
||||
"logging": {
|
||||
"console_level": null,
|
||||
"file_level": null,
|
||||
"file_path": "/home/bobby/.local/share/net.akkudoktor.eos/output/eos.log"
|
||||
},
|
||||
"devices": {
|
||||
"batteries": [
|
||||
{
|
||||
"device_id": "battery1",
|
||||
"capacity_wh": 8000,
|
||||
"charging_efficiency": 0.88,
|
||||
"discharging_efficiency": 0.88,
|
||||
"levelized_cost_of_storage_kwh": 0,
|
||||
"max_charge_power_w": 5000,
|
||||
"min_charge_power_w": 50,
|
||||
"charge_rates": [
|
||||
0,
|
||||
0.1,
|
||||
0.2,
|
||||
0.3,
|
||||
0.4,
|
||||
0.5,
|
||||
0.6,
|
||||
0.7,
|
||||
0.8,
|
||||
0.9,
|
||||
1
|
||||
],
|
||||
"min_soc_percentage": 0,
|
||||
"max_soc_percentage": 100,
|
||||
"measurement_key_soc_factor": "battery1-soc-factor",
|
||||
"measurement_key_power_l1_w": "battery1-power-l1-w",
|
||||
"measurement_key_power_l2_w": "battery1-power-l2-w",
|
||||
"measurement_key_power_l3_w": "battery1-power-l3-w",
|
||||
"measurement_key_power_3_phase_sym_w": "battery1-power-3-phase-sym-w",
|
||||
"measurement_keys": [
|
||||
"battery1-soc-factor",
|
||||
"battery1-power-l1-w",
|
||||
"battery1-power-l2-w",
|
||||
"battery1-power-l3-w",
|
||||
"battery1-power-3-phase-sym-w"
|
||||
]
|
||||
}
|
||||
],
|
||||
"max_batteries": 1,
|
||||
"electric_vehicles": [
|
||||
{
|
||||
"device_id": "ev11",
|
||||
"capacity_wh": 50000,
|
||||
"charging_efficiency": 0.88,
|
||||
"discharging_efficiency": 0.88,
|
||||
"levelized_cost_of_storage_kwh": 0,
|
||||
"max_charge_power_w": 5000,
|
||||
"min_charge_power_w": 50,
|
||||
"charge_rates": [
|
||||
0,
|
||||
0.1,
|
||||
0.2,
|
||||
0.3,
|
||||
0.4,
|
||||
0.5,
|
||||
0.6,
|
||||
0.7,
|
||||
0.8,
|
||||
0.9,
|
||||
1
|
||||
],
|
||||
"min_soc_percentage": 70,
|
||||
"max_soc_percentage": 100,
|
||||
"measurement_key_soc_factor": "ev11-soc-factor",
|
||||
"measurement_key_power_l1_w": "ev11-power-l1-w",
|
||||
"measurement_key_power_l2_w": "ev11-power-l2-w",
|
||||
"measurement_key_power_l3_w": "ev11-power-l3-w",
|
||||
"measurement_key_power_3_phase_sym_w": "ev11-power-3-phase-sym-w",
|
||||
"measurement_keys": [
|
||||
"ev11-soc-factor",
|
||||
"ev11-power-l1-w",
|
||||
"ev11-power-l2-w",
|
||||
"ev11-power-l3-w",
|
||||
"ev11-power-3-phase-sym-w"
|
||||
]
|
||||
}
|
||||
],
|
||||
"max_electric_vehicles": 1,
|
||||
"inverters": [
|
||||
{
|
||||
"device_id": "inverter1",
|
||||
"max_power_w": 10000,
|
||||
"battery_id": "battery1",
|
||||
"ac_to_dc_efficiency": 1,
|
||||
"dc_to_ac_efficiency": 1,
|
||||
"max_ac_charge_power_w": null,
|
||||
"measurement_keys": []
|
||||
}
|
||||
],
|
||||
"max_inverters": 1,
|
||||
"home_appliances": [
|
||||
{
|
||||
"device_id": "dishwasher1",
|
||||
"consumption_wh": 2000,
|
||||
"duration_h": 3,
|
||||
"time_windows": {
|
||||
"windows": [
|
||||
{
|
||||
"start_time": "08:00:00.000000 Europe/Berlin",
|
||||
"duration": "5 hours",
|
||||
"day_of_week": null,
|
||||
"date": null,
|
||||
"locale": null
|
||||
},
|
||||
{
|
||||
"start_time": "15:00:00.000000 Europe/Berlin",
|
||||
"duration": "3 hours",
|
||||
"day_of_week": null,
|
||||
"date": null,
|
||||
"locale": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"measurement_keys": []
|
||||
}
|
||||
],
|
||||
"max_home_appliances": 1,
|
||||
"measurement_keys": [
|
||||
"battery1-soc-factor",
|
||||
"battery1-power-l1-w",
|
||||
"battery1-power-l2-w",
|
||||
"battery1-power-l3-w",
|
||||
"battery1-power-3-phase-sym-w",
|
||||
"ev11-soc-factor",
|
||||
"ev11-power-l1-w",
|
||||
"ev11-power-l2-w",
|
||||
"ev11-power-l3-w",
|
||||
"ev11-power-3-phase-sym-w"
|
||||
]
|
||||
},
|
||||
"measurement": {
|
||||
"historic_hours": 17520,
|
||||
"load_emr_keys": null,
|
||||
"grid_export_emr_keys": null,
|
||||
"grid_import_emr_keys": null,
|
||||
"pv_production_emr_keys": null,
|
||||
"keys": []
|
||||
},
|
||||
"optimization": {
|
||||
"horizon_hours": 24,
|
||||
"interval": 3600,
|
||||
"algorithm": "GENETIC",
|
||||
"genetic": {
|
||||
"individuals": 300,
|
||||
"generations": 400,
|
||||
"seed": null,
|
||||
"penalties": {
|
||||
"ev_soc_miss": 10,
|
||||
"ac_charge_break_even": 1
|
||||
}
|
||||
},
|
||||
"keys": [
|
||||
"battery1_fault_op_factor",
|
||||
"battery1_fault_op_mode",
|
||||
"battery1_forced_charge_op_factor",
|
||||
"battery1_forced_charge_op_mode",
|
||||
"battery1_forced_discharge_op_factor",
|
||||
"battery1_forced_discharge_op_mode",
|
||||
"battery1_frequency_regulation_op_factor",
|
||||
"battery1_frequency_regulation_op_mode",
|
||||
"battery1_grid_support_export_op_factor",
|
||||
"battery1_grid_support_export_op_mode",
|
||||
"battery1_grid_support_import_op_factor",
|
||||
"battery1_grid_support_import_op_mode",
|
||||
"battery1_idle_op_factor",
|
||||
"battery1_idle_op_mode",
|
||||
"battery1_non_export_op_factor",
|
||||
"battery1_non_export_op_mode",
|
||||
"battery1_outage_supply_op_factor",
|
||||
"battery1_outage_supply_op_mode",
|
||||
"battery1_peak_shaving_op_factor",
|
||||
"battery1_peak_shaving_op_mode",
|
||||
"battery1_ramp_rate_control_op_factor",
|
||||
"battery1_ramp_rate_control_op_mode",
|
||||
"battery1_reserve_backup_op_factor",
|
||||
"battery1_reserve_backup_op_mode",
|
||||
"battery1_self_consumption_op_factor",
|
||||
"battery1_self_consumption_op_mode",
|
||||
"battery1_soc_factor",
|
||||
"costs_amt",
|
||||
"date_time",
|
||||
"ev11_fault_op_factor",
|
||||
"ev11_fault_op_mode",
|
||||
"ev11_forced_charge_op_factor",
|
||||
"ev11_forced_charge_op_mode",
|
||||
"ev11_forced_discharge_op_factor",
|
||||
"ev11_forced_discharge_op_mode",
|
||||
"ev11_frequency_regulation_op_factor",
|
||||
"ev11_frequency_regulation_op_mode",
|
||||
"ev11_grid_support_export_op_factor",
|
||||
"ev11_grid_support_export_op_mode",
|
||||
"ev11_grid_support_import_op_factor",
|
||||
"ev11_grid_support_import_op_mode",
|
||||
"ev11_idle_op_factor",
|
||||
"ev11_idle_op_mode",
|
||||
"ev11_non_export_op_factor",
|
||||
"ev11_non_export_op_mode",
|
||||
"ev11_outage_supply_op_factor",
|
||||
"ev11_outage_supply_op_mode",
|
||||
"ev11_peak_shaving_op_factor",
|
||||
"ev11_peak_shaving_op_mode",
|
||||
"ev11_ramp_rate_control_op_factor",
|
||||
"ev11_ramp_rate_control_op_mode",
|
||||
"ev11_reserve_backup_op_factor",
|
||||
"ev11_reserve_backup_op_mode",
|
||||
"ev11_self_consumption_op_factor",
|
||||
"ev11_self_consumption_op_mode",
|
||||
"ev11_soc_factor",
|
||||
"genetic_ac_charge_factor",
|
||||
"genetic_dc_charge_factor",
|
||||
"genetic_discharge_allowed_factor",
|
||||
"genetic_ev_charge_factor",
|
||||
"grid_consumption_energy_wh",
|
||||
"grid_feedin_energy_wh",
|
||||
"homeappliance1_energy_wh",
|
||||
"homeappliance1_off_op_factor",
|
||||
"homeappliance1_off_op_mode",
|
||||
"homeappliance1_run_op_factor",
|
||||
"homeappliance1_run_op_mode",
|
||||
"load_energy_wh",
|
||||
"losses_energy_wh",
|
||||
"revenue_amt"
|
||||
]
|
||||
},
|
||||
"prediction": {
|
||||
"hours": 48,
|
||||
"historic_hours": 48
|
||||
},
|
||||
"elecprice": {
|
||||
"provider": "ElecPriceAkkudoktor",
|
||||
"charges_kwh": null,
|
||||
"vat_rate": 1.19,
|
||||
"elecpriceimport": {
|
||||
"import_file_path": null,
|
||||
"import_json": null
|
||||
},
|
||||
"energycharts": {
|
||||
"bidding_zone": "DE-LU"
|
||||
},
|
||||
"providers": [
|
||||
"ElecPriceAkkudoktor",
|
||||
"ElecPriceEnergyCharts",
|
||||
"ElecPriceImport"
|
||||
]
|
||||
},
|
||||
"feedintariff": {
|
||||
"provider": "FeedInTariffFixed",
|
||||
"provider_settings": {
|
||||
"FeedInTariffFixed": {
|
||||
"feed_in_tariff_kwh": 0.078
|
||||
},
|
||||
"FeedInTariffImport": null
|
||||
},
|
||||
"providers": [
|
||||
"FeedInTariffFixed",
|
||||
"FeedInTariffImport"
|
||||
]
|
||||
},
|
||||
"load": {
|
||||
"provider": "LoadAkkudoktorAdjusted",
|
||||
"loadakkudoktor": {
|
||||
"loadakkudoktor_year_energy_kwh": 3000
|
||||
},
|
||||
"loadvrm": {
|
||||
"load_vrm_token": "your-token",
|
||||
"load_vrm_idsite": 12345
|
||||
},
|
||||
"loadimport": {
|
||||
"import_file_path": null,
|
||||
"import_json": null
|
||||
},
|
||||
"providers": [
|
||||
"LoadAkkudoktor",
|
||||
"LoadAkkudoktorAdjusted",
|
||||
"LoadVrm",
|
||||
"LoadImport"
|
||||
]
|
||||
},
|
||||
"pvforecast": {
|
||||
"provider": "PVForecastAkkudoktor",
|
||||
"provider_settings": {
|
||||
"PVForecastImport": null,
|
||||
"PVForecastVrm": null
|
||||
},
|
||||
"planes": [
|
||||
{
|
||||
"surface_tilt": 7,
|
||||
"surface_azimuth": 170,
|
||||
"userhorizon": [
|
||||
20,
|
||||
27,
|
||||
22,
|
||||
20
|
||||
],
|
||||
"peakpower": 5,
|
||||
"pvtechchoice": "crystSi",
|
||||
"mountingplace": "free",
|
||||
"loss": 14,
|
||||
"trackingtype": null,
|
||||
"optimal_surface_tilt": false,
|
||||
"optimalangles": false,
|
||||
"albedo": null,
|
||||
"module_model": null,
|
||||
"inverter_model": null,
|
||||
"inverter_paco": 10000,
|
||||
"modules_per_string": null,
|
||||
"strings_per_inverter": null
|
||||
},
|
||||
{
|
||||
"surface_tilt": 7,
|
||||
"surface_azimuth": 90,
|
||||
"userhorizon": [
|
||||
30,
|
||||
30,
|
||||
30,
|
||||
50
|
||||
],
|
||||
"peakpower": 4.8,
|
||||
"pvtechchoice": "crystSi",
|
||||
"mountingplace": "free",
|
||||
"loss": 14,
|
||||
"trackingtype": null,
|
||||
"optimal_surface_tilt": false,
|
||||
"optimalangles": false,
|
||||
"albedo": null,
|
||||
"module_model": null,
|
||||
"inverter_model": null,
|
||||
"inverter_paco": 10000,
|
||||
"modules_per_string": null,
|
||||
"strings_per_inverter": null
|
||||
},
|
||||
{
|
||||
"surface_tilt": 60,
|
||||
"surface_azimuth": 140,
|
||||
"userhorizon": [
|
||||
60,
|
||||
30,
|
||||
0,
|
||||
30
|
||||
],
|
||||
"peakpower": 1.4,
|
||||
"pvtechchoice": "crystSi",
|
||||
"mountingplace": "free",
|
||||
"loss": 14,
|
||||
"trackingtype": null,
|
||||
"optimal_surface_tilt": false,
|
||||
"optimalangles": false,
|
||||
"albedo": null,
|
||||
"module_model": null,
|
||||
"inverter_model": null,
|
||||
"inverter_paco": 2000,
|
||||
"modules_per_string": null,
|
||||
"strings_per_inverter": null
|
||||
},
|
||||
{
|
||||
"surface_tilt": 45,
|
||||
"surface_azimuth": 185,
|
||||
"userhorizon": [
|
||||
45,
|
||||
25,
|
||||
30,
|
||||
60
|
||||
],
|
||||
"peakpower": 1.6,
|
||||
"pvtechchoice": "crystSi",
|
||||
"mountingplace": "free",
|
||||
"loss": 14,
|
||||
"trackingtype": null,
|
||||
"optimal_surface_tilt": false,
|
||||
"optimalangles": false,
|
||||
"albedo": null,
|
||||
"module_model": null,
|
||||
"inverter_model": null,
|
||||
"inverter_paco": 1400,
|
||||
"modules_per_string": null,
|
||||
"strings_per_inverter": null
|
||||
}
|
||||
],
|
||||
"max_planes": 4,
|
||||
"providers": [
|
||||
"PVForecastAkkudoktor",
|
||||
"PVForecastVrm",
|
||||
"PVForecastImport"
|
||||
],
|
||||
"planes_peakpower": [
|
||||
5,
|
||||
4.8,
|
||||
1.4,
|
||||
1.6
|
||||
],
|
||||
"planes_azimuth": [
|
||||
170,
|
||||
90,
|
||||
140,
|
||||
185
|
||||
],
|
||||
"planes_tilt": [
|
||||
7,
|
||||
7,
|
||||
60,
|
||||
45
|
||||
],
|
||||
"planes_userhorizon": [
|
||||
[
|
||||
20,
|
||||
27,
|
||||
22,
|
||||
20
|
||||
],
|
||||
[
|
||||
30,
|
||||
30,
|
||||
30,
|
||||
50
|
||||
],
|
||||
[
|
||||
60,
|
||||
30,
|
||||
0,
|
||||
30
|
||||
],
|
||||
[
|
||||
45,
|
||||
25,
|
||||
30,
|
||||
60
|
||||
]
|
||||
],
|
||||
"planes_inverter_paco": [
|
||||
10000,
|
||||
10000,
|
||||
2000,
|
||||
1400
|
||||
]
|
||||
},
|
||||
"weather": {
|
||||
"provider": "BrightSky",
|
||||
"provider_settings": {
|
||||
"WeatherImport": null
|
||||
},
|
||||
"providers": [
|
||||
"BrightSky",
|
||||
"ClearOutside",
|
||||
"WeatherImport"
|
||||
]
|
||||
},
|
||||
"server": {
|
||||
"host": "127.0.0.1",
|
||||
"port": 8503,
|
||||
"verbose": false,
|
||||
"startup_eosdash": true,
|
||||
"eosdash_host": "127.0.0.1",
|
||||
"eosdash_port": 8504,
|
||||
"eosdash_supervise_interval_sec": 10
|
||||
},
|
||||
"utils": {},
|
||||
"adapter": {
|
||||
"provider": null,
|
||||
"homeassistant": {
|
||||
"config_entity_ids": null,
|
||||
"load_emr_entity_ids": null,
|
||||
"grid_export_emr_entity_ids": null,
|
||||
"grid_import_emr_entity_ids": null,
|
||||
"pv_production_emr_entity_ids": null,
|
||||
"device_measurement_entity_ids": null,
|
||||
"device_instruction_entity_ids": null,
|
||||
"solution_entity_ids": null,
|
||||
"homeassistant_entity_ids": [],
|
||||
"eos_solution_entity_ids": [
|
||||
"sensor.eos_battery1_fault_op_factor",
|
||||
"sensor.eos_battery1_fault_op_mode",
|
||||
"sensor.eos_battery1_forced_charge_op_factor",
|
||||
"sensor.eos_battery1_forced_charge_op_mode",
|
||||
"sensor.eos_battery1_forced_discharge_op_factor",
|
||||
"sensor.eos_battery1_forced_discharge_op_mode",
|
||||
"sensor.eos_battery1_frequency_regulation_op_factor",
|
||||
"sensor.eos_battery1_frequency_regulation_op_mode",
|
||||
"sensor.eos_battery1_grid_support_export_op_factor",
|
||||
"sensor.eos_battery1_grid_support_export_op_mode",
|
||||
"sensor.eos_battery1_grid_support_import_op_factor",
|
||||
"sensor.eos_battery1_grid_support_import_op_mode",
|
||||
"sensor.eos_battery1_idle_op_factor",
|
||||
"sensor.eos_battery1_idle_op_mode",
|
||||
"sensor.eos_battery1_non_export_op_factor",
|
||||
"sensor.eos_battery1_non_export_op_mode",
|
||||
"sensor.eos_battery1_outage_supply_op_factor",
|
||||
"sensor.eos_battery1_outage_supply_op_mode",
|
||||
"sensor.eos_battery1_peak_shaving_op_factor",
|
||||
"sensor.eos_battery1_peak_shaving_op_mode",
|
||||
"sensor.eos_battery1_ramp_rate_control_op_factor",
|
||||
"sensor.eos_battery1_ramp_rate_control_op_mode",
|
||||
"sensor.eos_battery1_reserve_backup_op_factor",
|
||||
"sensor.eos_battery1_reserve_backup_op_mode",
|
||||
"sensor.eos_battery1_self_consumption_op_factor",
|
||||
"sensor.eos_battery1_self_consumption_op_mode",
|
||||
"sensor.eos_battery1_soc_factor",
|
||||
"sensor.eos_costs_amt",
|
||||
"sensor.eos_date_time",
|
||||
"sensor.eos_ev11_fault_op_factor",
|
||||
"sensor.eos_ev11_fault_op_mode",
|
||||
"sensor.eos_ev11_forced_charge_op_factor",
|
||||
"sensor.eos_ev11_forced_charge_op_mode",
|
||||
"sensor.eos_ev11_forced_discharge_op_factor",
|
||||
"sensor.eos_ev11_forced_discharge_op_mode",
|
||||
"sensor.eos_ev11_frequency_regulation_op_factor",
|
||||
"sensor.eos_ev11_frequency_regulation_op_mode",
|
||||
"sensor.eos_ev11_grid_support_export_op_factor",
|
||||
"sensor.eos_ev11_grid_support_export_op_mode",
|
||||
"sensor.eos_ev11_grid_support_import_op_factor",
|
||||
"sensor.eos_ev11_grid_support_import_op_mode",
|
||||
"sensor.eos_ev11_idle_op_factor",
|
||||
"sensor.eos_ev11_idle_op_mode",
|
||||
"sensor.eos_ev11_non_export_op_factor",
|
||||
"sensor.eos_ev11_non_export_op_mode",
|
||||
"sensor.eos_ev11_outage_supply_op_factor",
|
||||
"sensor.eos_ev11_outage_supply_op_mode",
|
||||
"sensor.eos_ev11_peak_shaving_op_factor",
|
||||
"sensor.eos_ev11_peak_shaving_op_mode",
|
||||
"sensor.eos_ev11_ramp_rate_control_op_factor",
|
||||
"sensor.eos_ev11_ramp_rate_control_op_mode",
|
||||
"sensor.eos_ev11_reserve_backup_op_factor",
|
||||
"sensor.eos_ev11_reserve_backup_op_mode",
|
||||
"sensor.eos_ev11_self_consumption_op_factor",
|
||||
"sensor.eos_ev11_self_consumption_op_mode",
|
||||
"sensor.eos_ev11_soc_factor",
|
||||
"sensor.eos_genetic_ac_charge_factor",
|
||||
"sensor.eos_genetic_dc_charge_factor",
|
||||
"sensor.eos_genetic_discharge_allowed_factor",
|
||||
"sensor.eos_genetic_ev_charge_factor",
|
||||
"sensor.eos_grid_consumption_energy_wh",
|
||||
"sensor.eos_grid_feedin_energy_wh",
|
||||
"sensor.eos_homeappliance1_energy_wh",
|
||||
"sensor.eos_homeappliance1_off_op_factor",
|
||||
"sensor.eos_homeappliance1_off_op_mode",
|
||||
"sensor.eos_homeappliance1_run_op_factor",
|
||||
"sensor.eos_homeappliance1_run_op_mode",
|
||||
"sensor.eos_load_energy_wh",
|
||||
"sensor.eos_losses_energy_wh",
|
||||
"sensor.eos_revenue_amt"
|
||||
],
|
||||
"eos_device_instruction_entity_ids": [
|
||||
"sensor.eos_battery1",
|
||||
"sensor.eos_ev11",
|
||||
"sensor.eos_homeappliance1"
|
||||
]
|
||||
},
|
||||
"nodered": {
|
||||
"host": "127.0.0.1",
|
||||
"port": 1880
|
||||
},
|
||||
"providers": [
|
||||
"HomeAssistant",
|
||||
"NodeRED"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user