mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-02-26 19:06:20 +00:00
fix: Improve provider update error handling and add VRM provider settings validation (#887)
Some checks are pending
Bump Version / Bump Version Workflow (push) Waiting to run
docker-build / platform-excludes (push) Waiting to run
docker-build / build (push) Blocked by required conditions
docker-build / merge (push) Blocked by required conditions
pre-commit / pre-commit (push) Waiting to run
Run Pytest on Pull Request / test (push) Waiting to run
Some checks are pending
Bump Version / Bump Version Workflow (push) Waiting to run
docker-build / platform-excludes (push) Waiting to run
docker-build / build (push) Blocked by required conditions
docker-build / merge (push) Blocked by required conditions
pre-commit / pre-commit (push) Waiting to run
Run Pytest on Pull Request / test (push) Waiting to run
* fix: improve error handling for provider updates Distinguishes failures of active providers from inactive ones. Propagates errors only for enabled providers, allowing execution to continue if a non-active provider fails, which avoids unnecessary interruptions and improves robustness. * fix: add provider settings validation for forecast requests Prevents potential runtime errors by checking if provider settings are configured before accessing forecast credentials. Raises a clear error when settings are missing to help with debugging misconfigurations. * refactor(load): move provider settings to top-level fields Transitions load provider settings from a nested "provider_settings" object with provider-specific keys to dedicated top-level fields.\n\nRemoves the legacy "provider_settings" mapping and updates migration logic to ensure backward compatibility with existing configurations. * docs: update version numbers and documantation --------- Co-authored-by: Normann <github@koldrack.com>
This commit is contained in:
committed by
GitHub
parent
2ca9c930e5
commit
04420e66ab
@@ -120,7 +120,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"general": {
|
"general": {
|
||||||
"version": "0.2.0.dev2602242106748274",
|
"version": "0.2.0.dev2602250574650225",
|
||||||
"data_folder_path": "/home/user/.local/share/net.akkudoktoreos.net",
|
"data_folder_path": "/home/user/.local/share/net.akkudoktoreos.net",
|
||||||
"data_output_subpath": "output",
|
"data_output_subpath": "output",
|
||||||
"latitude": 52.52,
|
"latitude": 52.52,
|
||||||
@@ -128,10 +128,16 @@
|
|||||||
},
|
},
|
||||||
"load": {
|
"load": {
|
||||||
"provider": "LoadAkkudoktor",
|
"provider": "LoadAkkudoktor",
|
||||||
"provider_settings": {
|
"loadakkudoktor": {
|
||||||
"LoadAkkudoktor": null,
|
"loadakkudoktor_year_energy_kwh": null
|
||||||
"LoadVrm": null,
|
},
|
||||||
"LoadImport": null
|
"loadvrm": {
|
||||||
|
"load_vrm_token": "your-token",
|
||||||
|
"load_vrm_idsite": 12345
|
||||||
|
},
|
||||||
|
"loadimport": {
|
||||||
|
"import_file_path": null,
|
||||||
|
"import_json": null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"logging": {
|
"logging": {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
| latitude | `EOS_GENERAL__LATITUDE` | `Optional[float]` | `rw` | `52.52` | Latitude in decimal degrees between -90 and 90. North is positive (ISO 19115) (°) |
|
| latitude | `EOS_GENERAL__LATITUDE` | `Optional[float]` | `rw` | `52.52` | Latitude in decimal degrees between -90 and 90. North is positive (ISO 19115) (°) |
|
||||||
| longitude | `EOS_GENERAL__LONGITUDE` | `Optional[float]` | `rw` | `13.405` | Longitude in decimal degrees within -180 to 180 (°) |
|
| longitude | `EOS_GENERAL__LONGITUDE` | `Optional[float]` | `rw` | `13.405` | Longitude in decimal degrees within -180 to 180 (°) |
|
||||||
| timezone | | `Optional[str]` | `ro` | `N/A` | Computed timezone based on latitude and longitude. |
|
| timezone | | `Optional[str]` | `ro` | `N/A` | Computed timezone based on latitude and longitude. |
|
||||||
| version | `EOS_GENERAL__VERSION` | `str` | `rw` | `0.2.0.dev2602242106748274` | Configuration file version. Used to check compatibility. |
|
| version | `EOS_GENERAL__VERSION` | `str` | `rw` | `0.2.0.dev2602250574650225` | Configuration file version. Used to check compatibility. |
|
||||||
:::
|
:::
|
||||||
<!-- pyml enable line-length -->
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"general": {
|
"general": {
|
||||||
"version": "0.2.0.dev2602242106748274",
|
"version": "0.2.0.dev2602250574650225",
|
||||||
"data_folder_path": "/home/user/.local/share/net.akkudoktoreos.net",
|
"data_folder_path": "/home/user/.local/share/net.akkudoktoreos.net",
|
||||||
"data_output_subpath": "output",
|
"data_output_subpath": "output",
|
||||||
"latitude": 52.52,
|
"latitude": 52.52,
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"general": {
|
"general": {
|
||||||
"version": "0.2.0.dev2602242106748274",
|
"version": "0.2.0.dev2602250574650225",
|
||||||
"data_folder_path": "/home/user/.local/share/net.akkudoktoreos.net",
|
"data_folder_path": "/home/user/.local/share/net.akkudoktoreos.net",
|
||||||
"data_output_subpath": "output",
|
"data_output_subpath": "output",
|
||||||
"latitude": 52.52,
|
"latitude": 52.52,
|
||||||
|
|||||||
@@ -7,8 +7,10 @@
|
|||||||
|
|
||||||
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
|
| loadakkudoktor | `EOS_LOAD__LOADAKKUDOKTOR` | `LoadAkkudoktorCommonSettings` | `rw` | `required` | LoadAkkudoktor provider settings. |
|
||||||
|
| loadimport | `EOS_LOAD__LOADIMPORT` | `LoadImportCommonSettings` | `rw` | `required` | LoadImport provider settings. |
|
||||||
|
| loadvrm | `EOS_LOAD__LOADVRM` | `LoadVrmCommonSettings` | `rw` | `required` | LoadVrm provider settings. |
|
||||||
| provider | `EOS_LOAD__PROVIDER` | `Optional[str]` | `rw` | `None` | Load provider id of provider to be used. |
|
| provider | `EOS_LOAD__PROVIDER` | `Optional[str]` | `rw` | `None` | Load provider id of provider to be used. |
|
||||||
| provider_settings | `EOS_LOAD__PROVIDER_SETTINGS` | `LoadCommonProviderSettings` | `rw` | `required` | Provider settings |
|
|
||||||
| providers | | `list[str]` | `ro` | `N/A` | Available load provider ids. |
|
| providers | | `list[str]` | `ro` | `N/A` | Available load provider ids. |
|
||||||
:::
|
:::
|
||||||
<!-- pyml enable line-length -->
|
<!-- pyml enable line-length -->
|
||||||
@@ -22,10 +24,16 @@
|
|||||||
{
|
{
|
||||||
"load": {
|
"load": {
|
||||||
"provider": "LoadAkkudoktor",
|
"provider": "LoadAkkudoktor",
|
||||||
"provider_settings": {
|
"loadakkudoktor": {
|
||||||
"LoadAkkudoktor": null,
|
"loadakkudoktor_year_energy_kwh": null
|
||||||
"LoadVrm": null,
|
},
|
||||||
"LoadImport": null
|
"loadvrm": {
|
||||||
|
"load_vrm_token": "your-token",
|
||||||
|
"load_vrm_idsite": 12345
|
||||||
|
},
|
||||||
|
"loadimport": {
|
||||||
|
"import_file_path": null,
|
||||||
|
"import_json": null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,10 +49,16 @@
|
|||||||
{
|
{
|
||||||
"load": {
|
"load": {
|
||||||
"provider": "LoadAkkudoktor",
|
"provider": "LoadAkkudoktor",
|
||||||
"provider_settings": {
|
"loadakkudoktor": {
|
||||||
"LoadAkkudoktor": null,
|
"loadakkudoktor_year_energy_kwh": null
|
||||||
"LoadVrm": null,
|
},
|
||||||
"LoadImport": null
|
"loadvrm": {
|
||||||
|
"load_vrm_token": "your-token",
|
||||||
|
"load_vrm_idsite": 12345
|
||||||
|
},
|
||||||
|
"loadimport": {
|
||||||
|
"import_file_path": null,
|
||||||
|
"import_json": null
|
||||||
},
|
},
|
||||||
"providers": [
|
"providers": [
|
||||||
"LoadAkkudoktor",
|
"LoadAkkudoktor",
|
||||||
@@ -57,43 +71,10 @@
|
|||||||
```
|
```
|
||||||
<!-- pyml enable line-length -->
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
### Common settings for load data import from file or JSON string
|
|
||||||
|
|
||||||
<!-- pyml disable line-length -->
|
|
||||||
:::{table} load::provider_settings::LoadImport
|
|
||||||
:widths: 10 10 5 5 30
|
|
||||||
:align: left
|
|
||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
|
||||||
| import_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | Path to the file to import load data from. |
|
|
||||||
| import_json | `Optional[str]` | `rw` | `None` | JSON string, dictionary of load forecast value lists. |
|
|
||||||
:::
|
|
||||||
<!-- pyml enable line-length -->
|
|
||||||
|
|
||||||
<!-- pyml disable no-emphasis-as-heading -->
|
|
||||||
**Example Input/Output**
|
|
||||||
<!-- pyml enable no-emphasis-as-heading -->
|
|
||||||
|
|
||||||
<!-- pyml disable line-length -->
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"load": {
|
|
||||||
"provider_settings": {
|
|
||||||
"LoadImport": {
|
|
||||||
"import_file_path": null,
|
|
||||||
"import_json": "{\"load0_mean\": [676.71, 876.19, 527.13]}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
<!-- pyml enable line-length -->
|
|
||||||
|
|
||||||
### Common settings for load forecast VRM API
|
### Common settings for load forecast VRM API
|
||||||
|
|
||||||
<!-- pyml disable line-length -->
|
<!-- pyml disable line-length -->
|
||||||
:::{table} load::provider_settings::LoadVrm
|
:::{table} load::loadvrm
|
||||||
:widths: 10 10 5 5 30
|
:widths: 10 10 5 5 30
|
||||||
:align: left
|
:align: left
|
||||||
|
|
||||||
@@ -112,11 +93,40 @@
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"load": {
|
"load": {
|
||||||
"provider_settings": {
|
"loadvrm": {
|
||||||
"LoadVrm": {
|
"load_vrm_token": "your-token",
|
||||||
"load_vrm_token": "your-token",
|
"load_vrm_idsite": 12345
|
||||||
"load_vrm_idsite": 12345
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### Common settings for load data import from file or JSON string
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} load::loadimport
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| import_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | Path to the file to import load data from. |
|
||||||
|
| import_json | `Optional[str]` | `rw` | `None` | JSON string, dictionary of load forecast value lists. |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"load": {
|
||||||
|
"loadimport": {
|
||||||
|
"import_file_path": null,
|
||||||
|
"import_json": "{\"load0_mean\": [676.71, 876.19, 527.13]}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,7 +136,7 @@
|
|||||||
### Common settings for load data import from file
|
### Common settings for load data import from file
|
||||||
|
|
||||||
<!-- pyml disable line-length -->
|
<!-- pyml disable line-length -->
|
||||||
:::{table} load::provider_settings::LoadAkkudoktor
|
:::{table} load::loadakkudoktor
|
||||||
:widths: 10 10 5 5 30
|
:widths: 10 10 5 5 30
|
||||||
:align: left
|
:align: left
|
||||||
|
|
||||||
@@ -144,43 +154,8 @@
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"load": {
|
"load": {
|
||||||
"provider_settings": {
|
"loadakkudoktor": {
|
||||||
"LoadAkkudoktor": {
|
"loadakkudoktor_year_energy_kwh": 40421.0
|
||||||
"loadakkudoktor_year_energy_kwh": 40421.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
<!-- pyml enable line-length -->
|
|
||||||
|
|
||||||
### Load Prediction Provider Configuration
|
|
||||||
|
|
||||||
<!-- pyml disable line-length -->
|
|
||||||
:::{table} load::provider_settings
|
|
||||||
:widths: 10 10 5 5 30
|
|
||||||
:align: left
|
|
||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
|
||||||
| LoadAkkudoktor | `Optional[akkudoktoreos.prediction.loadakkudoktor.LoadAkkudoktorCommonSettings]` | `rw` | `None` | LoadAkkudoktor settings |
|
|
||||||
| LoadImport | `Optional[akkudoktoreos.prediction.loadimport.LoadImportCommonSettings]` | `rw` | `None` | LoadImport settings |
|
|
||||||
| LoadVrm | `Optional[akkudoktoreos.prediction.loadvrm.LoadVrmCommonSettings]` | `rw` | `None` | LoadVrm settings |
|
|
||||||
:::
|
|
||||||
<!-- pyml enable line-length -->
|
|
||||||
|
|
||||||
<!-- pyml disable no-emphasis-as-heading -->
|
|
||||||
**Example Input/Output**
|
|
||||||
<!-- pyml enable no-emphasis-as-heading -->
|
|
||||||
|
|
||||||
<!-- pyml disable line-length -->
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"load": {
|
|
||||||
"provider_settings": {
|
|
||||||
"LoadAkkudoktor": null,
|
|
||||||
"LoadVrm": null,
|
|
||||||
"LoadImport": null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Akkudoktor-EOS
|
# Akkudoktor-EOS
|
||||||
|
|
||||||
**Version**: `v0.2.0.dev2602242106748274`
|
**Version**: `v0.2.0.dev2602250574650225`
|
||||||
|
|
||||||
<!-- pyml disable line-length -->
|
<!-- 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.
|
**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.
|
||||||
|
|||||||
96
openapi.json
96
openapi.json
@@ -8,7 +8,7 @@
|
|||||||
"name": "Apache 2.0",
|
"name": "Apache 2.0",
|
||||||
"url": "https://www.apache.org/licenses/LICENSE-2.0.html"
|
"url": "https://www.apache.org/licenses/LICENSE-2.0.html"
|
||||||
},
|
},
|
||||||
"version": "v0.2.0.dev2602242106748274"
|
"version": "v0.2.0.dev2602250574650225"
|
||||||
},
|
},
|
||||||
"paths": {
|
"paths": {
|
||||||
"/v1/admin/cache/clear": {
|
"/v1/admin/cache/clear": {
|
||||||
@@ -4451,7 +4451,7 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"title": "Version",
|
"title": "Version",
|
||||||
"description": "Configuration file version. Used to check compatibility.",
|
"description": "Configuration file version. Used to check compatibility.",
|
||||||
"default": "0.2.0.dev2602242106748274"
|
"default": "0.2.0.dev2602250574650225"
|
||||||
},
|
},
|
||||||
"data_folder_path": {
|
"data_folder_path": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -4514,7 +4514,7 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"title": "Version",
|
"title": "Version",
|
||||||
"description": "Configuration file version. Used to check compatibility.",
|
"description": "Configuration file version. Used to check compatibility.",
|
||||||
"default": "0.2.0.dev2602242106748274"
|
"default": "0.2.0.dev2602250574650225"
|
||||||
},
|
},
|
||||||
"data_folder_path": {
|
"data_folder_path": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -5942,55 +5942,6 @@
|
|||||||
"title": "LoadAkkudoktorCommonSettings",
|
"title": "LoadAkkudoktorCommonSettings",
|
||||||
"description": "Common settings for load data import from file."
|
"description": "Common settings for load data import from file."
|
||||||
},
|
},
|
||||||
"LoadCommonProviderSettings": {
|
|
||||||
"properties": {
|
|
||||||
"LoadAkkudoktor": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/LoadAkkudoktorCommonSettings"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "LoadAkkudoktor settings",
|
|
||||||
"examples": [
|
|
||||||
null
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"LoadVrm": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/LoadVrmCommonSettings"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "LoadVrm settings",
|
|
||||||
"examples": [
|
|
||||||
null
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"LoadImport": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/LoadImportCommonSettings"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "LoadImport settings",
|
|
||||||
"examples": [
|
|
||||||
null
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object",
|
|
||||||
"title": "LoadCommonProviderSettings",
|
|
||||||
"description": "Load Prediction Provider Configuration."
|
|
||||||
},
|
|
||||||
"LoadCommonSettings-Input": {
|
"LoadCommonSettings-Input": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"provider": {
|
"provider": {
|
||||||
@@ -6008,12 +5959,17 @@
|
|||||||
"LoadAkkudoktor"
|
"LoadAkkudoktor"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"provider_settings": {
|
"loadakkudoktor": {
|
||||||
"$ref": "#/components/schemas/LoadCommonProviderSettings",
|
"$ref": "#/components/schemas/LoadAkkudoktorCommonSettings",
|
||||||
"description": "Provider settings",
|
"description": "LoadAkkudoktor provider settings."
|
||||||
"examples": [
|
},
|
||||||
{}
|
"loadvrm": {
|
||||||
]
|
"$ref": "#/components/schemas/LoadVrmCommonSettings",
|
||||||
|
"description": "LoadVrm provider settings."
|
||||||
|
},
|
||||||
|
"loadimport": {
|
||||||
|
"$ref": "#/components/schemas/LoadImportCommonSettings",
|
||||||
|
"description": "LoadImport provider settings."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -6037,12 +5993,17 @@
|
|||||||
"LoadAkkudoktor"
|
"LoadAkkudoktor"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"provider_settings": {
|
"loadakkudoktor": {
|
||||||
"$ref": "#/components/schemas/LoadCommonProviderSettings",
|
"$ref": "#/components/schemas/LoadAkkudoktorCommonSettings",
|
||||||
"description": "Provider settings",
|
"description": "LoadAkkudoktor provider settings."
|
||||||
"examples": [
|
},
|
||||||
{}
|
"loadvrm": {
|
||||||
]
|
"$ref": "#/components/schemas/LoadVrmCommonSettings",
|
||||||
|
"description": "LoadVrm provider settings."
|
||||||
|
},
|
||||||
|
"loadimport": {
|
||||||
|
"$ref": "#/components/schemas/LoadImportCommonSettings",
|
||||||
|
"description": "LoadImport provider settings."
|
||||||
},
|
},
|
||||||
"providers": {
|
"providers": {
|
||||||
"items": {
|
"items": {
|
||||||
@@ -8785,13 +8746,6 @@
|
|||||||
"type": {
|
"type": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"title": "Error Type"
|
"title": "Error Type"
|
||||||
},
|
|
||||||
"input": {
|
|
||||||
"title": "Input"
|
|
||||||
},
|
|
||||||
"ctx": {
|
|
||||||
"type": "object",
|
|
||||||
"title": "Context"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|||||||
@@ -43,16 +43,21 @@ MIGRATION_MAP: Dict[
|
|||||||
# 0.2.0 -> 0.2.0+dev
|
# 0.2.0 -> 0.2.0+dev
|
||||||
"elecprice/provider_settings/ElecPriceImport/import_file_path": "elecprice/elecpriceimport/import_file_path",
|
"elecprice/provider_settings/ElecPriceImport/import_file_path": "elecprice/elecpriceimport/import_file_path",
|
||||||
"elecprice/provider_settings/ElecPriceImport/import_json": "elecprice/elecpriceimport/import_json",
|
"elecprice/provider_settings/ElecPriceImport/import_json": "elecprice/elecpriceimport/import_json",
|
||||||
|
"load/provider_settings/LoadAkkudoktor/loadakkudoktor_year_energy_kwh": "load/loadakkudoktor/loadakkudoktor_year_energy_kwh",
|
||||||
|
"load/provider_settings/LoadVrm/load_vrm_idsite": "load/loadvrm/load_vrm_idsite",
|
||||||
|
"load/provider_settings/LoadVrm/load_vrm_token": "load/loadvrm/load_vrm_token",
|
||||||
|
"load/provider_settings/LoadImport/import_file_path": "load/loadimport/import_file_path",
|
||||||
|
"load/provider_settings/LoadImport/import_json": "load/loadimport/import_json",
|
||||||
# 0.1.0 -> 0.2.0+dev
|
# 0.1.0 -> 0.2.0+dev
|
||||||
"devices/batteries/0/initial_soc_percentage": None,
|
"devices/batteries/0/initial_soc_percentage": None,
|
||||||
"devices/electric_vehicles/0/initial_soc_percentage": None,
|
"devices/electric_vehicles/0/initial_soc_percentage": None,
|
||||||
"elecprice/provider_settings/import_file_path": "elecprice/elecpriceimport/import_file_path",
|
"elecprice/provider_settings/import_file_path": "elecprice/elecpriceimport/import_file_path",
|
||||||
"elecprice/provider_settings/import_json": "elecprice/elecpriceimport/import_json",
|
"elecprice/provider_settings/import_json": "elecprice/elecpriceimport/import_json",
|
||||||
"load/provider_settings/import_file_path": "load/provider_settings/LoadImport/import_file_path",
|
"load/provider_settings/import_file_path": "load/loadimport/import_file_path",
|
||||||
"load/provider_settings/import_json": "load/provider_settings/LoadImport/import_json",
|
"load/provider_settings/import_json": "load/loadimport/import_json",
|
||||||
"load/provider_settings/loadakkudoktor_year_energy": "load/provider_settings/LoadAkkudoktor/loadakkudoktor_year_energy_kwh",
|
"load/provider_settings/loadakkudoktor_year_energy": "load/loadakkudoktor/loadakkudoktor_year_energy_kwh",
|
||||||
"load/provider_settings/load_vrm_idsite": "load/provider_settings/LoadVrm/load_vrm_idsite",
|
"load/provider_settings/load_vrm_idsite": "load/loadvrm/load_vrm_idsite",
|
||||||
"load/provider_settings/load_vrm_token": "load/provider_settings/LoadVrm/load_vrm_token",
|
"load/provider_settings/load_vrm_token": "load/loadvrm/load_vrm_token",
|
||||||
"logging/level": "logging/console_level",
|
"logging/level": "logging/console_level",
|
||||||
"logging/root_level": None,
|
"logging/root_level": None,
|
||||||
"measurement/load0_name": "measurement/load_emr_keys/0",
|
"measurement/load0_name": "measurement/load_emr_keys/0",
|
||||||
|
|||||||
@@ -1982,8 +1982,14 @@ class DataContainer(SingletonMixin, DataABC, MutableMapping):
|
|||||||
provider.update_data(force_enable=force_enable, force_update=force_update)
|
provider.update_data(force_enable=force_enable, force_update=force_update)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
error = f"Provider {provider.provider_id()} fails on update - enabled={provider.enabled()}, force_enable={force_enable}, force_update={force_update}: {ex}"
|
error = f"Provider {provider.provider_id()} fails on update - enabled={provider.enabled()}, force_enable={force_enable}, force_update={force_update}: {ex}"
|
||||||
logger.error(error)
|
if provider.enabled():
|
||||||
raise RuntimeError(error)
|
# The active provider failed — this is a real error worth propagating.
|
||||||
|
logger.error(error)
|
||||||
|
raise RuntimeError(error)
|
||||||
|
else:
|
||||||
|
# A non-active provider failed (e.g. missing config while force_enable=True).
|
||||||
|
# Log as warning and continue so the remaining providers still run.
|
||||||
|
logger.warning(error)
|
||||||
|
|
||||||
def key_to_series(
|
def key_to_series(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -337,10 +337,8 @@ class GeneticOptimizationParameters(
|
|||||||
{
|
{
|
||||||
"load": {
|
"load": {
|
||||||
"provider": "LoadAkkudoktor",
|
"provider": "LoadAkkudoktor",
|
||||||
"provider_settings": {
|
"loadakkudoktor": {
|
||||||
"LoadAkkudoktor": {
|
"loadakkudoktor_year_energy_kwh": "3000",
|
||||||
"loadakkudoktor_year_energy_kwh": "3000",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,21 +28,6 @@ def load_providers() -> list[str]:
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class LoadCommonProviderSettings(SettingsBaseModel):
|
|
||||||
"""Load Prediction Provider Configuration."""
|
|
||||||
|
|
||||||
LoadAkkudoktor: Optional[LoadAkkudoktorCommonSettings] = Field(
|
|
||||||
default=None,
|
|
||||||
json_schema_extra={"description": "LoadAkkudoktor settings", "examples": [None]},
|
|
||||||
)
|
|
||||||
LoadVrm: Optional[LoadVrmCommonSettings] = Field(
|
|
||||||
default=None, json_schema_extra={"description": "LoadVrm settings", "examples": [None]}
|
|
||||||
)
|
|
||||||
LoadImport: Optional[LoadImportCommonSettings] = Field(
|
|
||||||
default=None, json_schema_extra={"description": "LoadImport settings", "examples": [None]}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class LoadCommonSettings(SettingsBaseModel):
|
class LoadCommonSettings(SettingsBaseModel):
|
||||||
"""Load Prediction Configuration."""
|
"""Load Prediction Configuration."""
|
||||||
|
|
||||||
@@ -54,19 +39,19 @@ class LoadCommonSettings(SettingsBaseModel):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
provider_settings: LoadCommonProviderSettings = Field(
|
loadakkudoktor: LoadAkkudoktorCommonSettings = Field(
|
||||||
default_factory=LoadCommonProviderSettings,
|
default_factory=LoadAkkudoktorCommonSettings,
|
||||||
json_schema_extra={
|
json_schema_extra={"description": "LoadAkkudoktor provider settings."},
|
||||||
"description": "Provider settings",
|
)
|
||||||
"examples": [
|
|
||||||
# Example 1: Empty/default settings (all providers None)
|
loadvrm: LoadVrmCommonSettings = Field(
|
||||||
{
|
default_factory=LoadVrmCommonSettings,
|
||||||
"LoadAkkudoktor": None,
|
json_schema_extra={"description": "LoadVrm provider settings."},
|
||||||
"LoadVrm": None,
|
)
|
||||||
"LoadImport": None,
|
|
||||||
},
|
loadimport: LoadImportCommonSettings = Field(
|
||||||
],
|
default_factory=LoadImportCommonSettings,
|
||||||
},
|
json_schema_extra={"description": "LoadImport provider settings."},
|
||||||
)
|
)
|
||||||
|
|
||||||
@computed_field # type: ignore[prop-decorator]
|
@computed_field # type: ignore[prop-decorator]
|
||||||
|
|||||||
@@ -56,9 +56,7 @@ class LoadAkkudoktor(LoadProvider):
|
|||||||
)
|
)
|
||||||
# Calculate values in W by relative profile data and yearly consumption given in kWh
|
# Calculate values in W by relative profile data and yearly consumption given in kWh
|
||||||
data_year_energy = (
|
data_year_energy = (
|
||||||
profile_data
|
profile_data * self.config.load.loadakkudoktor.loadakkudoktor_year_energy_kwh * 1000
|
||||||
* self.config.load.provider_settings.LoadAkkudoktor.loadakkudoktor_year_energy_kwh
|
|
||||||
* 1000
|
|
||||||
)
|
)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
error_msg = f"Error: File {load_file} not found."
|
error_msg = f"Error: File {load_file} not found."
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ format, enabling consistent access to forecasted and historical load attributes.
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
from pydantic import Field, field_validator
|
from pydantic import Field, field_validator
|
||||||
|
|
||||||
from akkudoktoreos.config.configabc import SettingsBaseModel
|
from akkudoktoreos.config.configabc import SettingsBaseModel
|
||||||
@@ -64,14 +63,7 @@ class LoadImport(LoadProvider, PredictionImportProvider):
|
|||||||
return "LoadImport"
|
return "LoadImport"
|
||||||
|
|
||||||
def _update_data(self, force_update: Optional[bool] = False) -> None:
|
def _update_data(self, force_update: Optional[bool] = False) -> None:
|
||||||
if self.config.load.provider_settings.LoadImport is None:
|
if self.config.load.loadimport.import_file_path:
|
||||||
logger.debug(f"{self.provider_id()} data update without provider settings.")
|
self.import_from_file(self.config.load.loadimport.import_file_path, key_prefix="load")
|
||||||
return
|
if self.config.load.loadimport.import_json:
|
||||||
if self.config.load.provider_settings.LoadImport.import_file_path:
|
self.import_from_json(self.config.load.loadimport.import_json, key_prefix="load")
|
||||||
self.import_from_file(
|
|
||||||
self.config.provider_settings.LoadImport.import_file_path, key_prefix="load"
|
|
||||||
)
|
|
||||||
if self.config.load.provider_settings.LoadImport.import_json:
|
|
||||||
self.import_from_json(
|
|
||||||
self.config.load.provider_settings.LoadImport.import_json, key_prefix="load"
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -62,8 +62,9 @@ class LoadVrm(LoadProvider):
|
|||||||
def _request_forecast(self, start_ts: int, end_ts: int) -> VrmForecastResponse:
|
def _request_forecast(self, start_ts: int, end_ts: int) -> VrmForecastResponse:
|
||||||
"""Fetch forecast data from Victron VRM API."""
|
"""Fetch forecast data from Victron VRM API."""
|
||||||
base_url = "https://vrmapi.victronenergy.com/v2/installations"
|
base_url = "https://vrmapi.victronenergy.com/v2/installations"
|
||||||
installation_id = self.config.load.provider_settings.LoadVrm.load_vrm_idsite
|
vrm_settings = self.config.load.loadvrm
|
||||||
api_token = self.config.load.provider_settings.LoadVrm.load_vrm_token
|
installation_id = vrm_settings.load_vrm_idsite
|
||||||
|
api_token = vrm_settings.load_vrm_token
|
||||||
|
|
||||||
url = f"{base_url}/{installation_id}/stats?type=forecast&start={start_ts}&end={end_ts}&interval=hours"
|
url = f"{base_url}/{installation_id}/stats?type=forecast&start={start_ts}&end={end_ts}&interval=hours"
|
||||||
headers = {"X-Authorization": f"Token {api_token}", "Content-Type": "application/json"}
|
headers = {"X-Authorization": f"Token {api_token}", "Content-Type": "application/json"}
|
||||||
@@ -85,6 +86,9 @@ class LoadVrm(LoadProvider):
|
|||||||
|
|
||||||
def _update_data(self, force_update: Optional[bool] = False) -> None:
|
def _update_data(self, force_update: Optional[bool] = False) -> None:
|
||||||
"""Fetch and store VRM load forecast as loadforecast_power_w and related values."""
|
"""Fetch and store VRM load forecast as loadforecast_power_w and related values."""
|
||||||
|
if self.enabled is False:
|
||||||
|
logger.info("LoadVrm is disabled, skipping update.")
|
||||||
|
return
|
||||||
start_date = self.ems_start_datetime.start_of("day")
|
start_date = self.ems_start_datetime.start_of("day")
|
||||||
end_date = self.ems_start_datetime.add(hours=self.config.prediction.hours)
|
end_date = self.ems_start_datetime.add(hours=self.config.prediction.hours)
|
||||||
start_ts = int(start_date.timestamp())
|
start_ts = int(start_date.timestamp())
|
||||||
|
|||||||
@@ -85,6 +85,9 @@ class PVForecastVrm(PVForecastProvider):
|
|||||||
|
|
||||||
def _update_data(self, force_update: Optional[bool] = False) -> None:
|
def _update_data(self, force_update: Optional[bool] = False) -> None:
|
||||||
"""Update forecast data in the PVForecastDataRecord format."""
|
"""Update forecast data in the PVForecastDataRecord format."""
|
||||||
|
if self.enabled is False:
|
||||||
|
logger.info("PVForecastVrm is disabled, skipping update.")
|
||||||
|
return
|
||||||
start_date = self.ems_start_datetime.start_of("day")
|
start_date = self.ems_start_datetime.start_of("day")
|
||||||
end_date = self.ems_start_datetime.add(hours=self.config.prediction.hours)
|
end_date = self.ems_start_datetime.add(hours=self.config.prediction.hours)
|
||||||
start_ts = int(start_date.timestamp())
|
start_ts = int(start_date.timestamp())
|
||||||
|
|||||||
@@ -154,9 +154,7 @@ def LoadForecast(predictions: pd.DataFrame, config: dict, date_time_tz: str, dar
|
|||||||
source = ColumnDataSource(predictions)
|
source = ColumnDataSource(predictions)
|
||||||
provider = config["load"]["provider"]
|
provider = config["load"]["provider"]
|
||||||
if provider == "LoadAkkudoktorAdjusted":
|
if provider == "LoadAkkudoktorAdjusted":
|
||||||
year_energy = config["load"]["provider_settings"]["LoadAkkudoktor"][
|
year_energy = config["load"]["loadakkudoktor"]["loadakkudoktor_year_energy_kwh"]
|
||||||
"loadakkudoktor_year_energy_kwh"
|
|
||||||
]
|
|
||||||
provider = f"{provider}, {year_energy} kWh"
|
provider = f"{provider}, {year_energy} kWh"
|
||||||
|
|
||||||
plot = figure(
|
plot = figure(
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ from akkudoktoreos.optimization.genetic.geneticparams import (
|
|||||||
from akkudoktoreos.optimization.genetic.geneticsolution import GeneticSolution
|
from akkudoktoreos.optimization.genetic.geneticsolution import GeneticSolution
|
||||||
from akkudoktoreos.optimization.optimization import OptimizationSolution
|
from akkudoktoreos.optimization.optimization import OptimizationSolution
|
||||||
from akkudoktoreos.prediction.elecprice import ElecPriceCommonSettings
|
from akkudoktoreos.prediction.elecprice import ElecPriceCommonSettings
|
||||||
from akkudoktoreos.prediction.load import LoadCommonProviderSettings, LoadCommonSettings
|
from akkudoktoreos.prediction.load import LoadCommonSettings
|
||||||
from akkudoktoreos.prediction.loadakkudoktor import LoadAkkudoktorCommonSettings
|
from akkudoktoreos.prediction.loadakkudoktor import LoadAkkudoktorCommonSettings
|
||||||
from akkudoktoreos.prediction.pvforecast import PVForecastCommonSettings
|
from akkudoktoreos.prediction.pvforecast import PVForecastCommonSettings
|
||||||
from akkudoktoreos.server.rest.cli import cli_apply_args_to_config, cli_parse_args
|
from akkudoktoreos.server.rest.cli import cli_apply_args_to_config, cli_parse_args
|
||||||
@@ -1074,10 +1074,8 @@ async def fastapi_gesamtlast(request: GesamtlastRequest) -> list[float]:
|
|||||||
},
|
},
|
||||||
"load": {
|
"load": {
|
||||||
"provider": "LoadAkkudoktorAdjusted",
|
"provider": "LoadAkkudoktorAdjusted",
|
||||||
"provider_settings": {
|
"loadakkudoktor": {
|
||||||
"LoadAkkudoktor": {
|
"loadakkudoktor_year_energy_kwh": request.year_energy,
|
||||||
"loadakkudoktor_year_energy_kwh": request.year_energy,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"measurement": {
|
"measurement": {
|
||||||
@@ -1174,10 +1172,8 @@ async def fastapi_gesamtlast_simple(year_energy: float) -> list[float]:
|
|||||||
settings = SettingsEOS(
|
settings = SettingsEOS(
|
||||||
load=LoadCommonSettings(
|
load=LoadCommonSettings(
|
||||||
provider="LoadAkkudoktor",
|
provider="LoadAkkudoktor",
|
||||||
provider_settings=LoadCommonProviderSettings(
|
loadakkudoktor=LoadAkkudoktorCommonSettings(
|
||||||
LoadAkkudoktor=LoadAkkudoktorCommonSettings(
|
loadakkudoktor_year_energy_kwh=year_energy / 1000, # Convert to kWh
|
||||||
loadakkudoktor_year_energy_kwh=year_energy / 1000, # Convert to kWh
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -97,10 +97,8 @@ def prepare_optimization_real_parameters() -> GeneticOptimizationParameters:
|
|||||||
# Load Forecast
|
# Load Forecast
|
||||||
"load": {
|
"load": {
|
||||||
"provider": "LoadAkkudoktor",
|
"provider": "LoadAkkudoktor",
|
||||||
"provider_settings": {
|
"loadakkudoktor": {
|
||||||
"LoadAkkudoktor": {
|
"loadakkudoktor_year_energy_kwh": 5000, # Energy consumption per year in kWh
|
||||||
"loadakkudoktor_year_energy_kwh": 5000, # Energy consumption per year in kWh
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
# -- Simulations --
|
# -- Simulations --
|
||||||
|
|||||||
@@ -20,16 +20,14 @@ def loadakkudoktor(config_eos):
|
|||||||
settings = {
|
settings = {
|
||||||
"load": {
|
"load": {
|
||||||
"provider": "LoadAkkudoktor",
|
"provider": "LoadAkkudoktor",
|
||||||
"provider_settings": {
|
"loadakkudoktor": {
|
||||||
"LoadAkkudoktor": {
|
"loadakkudoktor_year_energy_kwh": "1000",
|
||||||
"loadakkudoktor_year_energy_kwh": "1000",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
config_eos.merge_settings_from_dict(settings)
|
config_eos.merge_settings_from_dict(settings)
|
||||||
assert config_eos.load.provider == "LoadAkkudoktor"
|
assert config_eos.load.provider == "LoadAkkudoktor"
|
||||||
assert config_eos.load.provider_settings.LoadAkkudoktor.loadakkudoktor_year_energy_kwh == 1000
|
assert config_eos.load.loadakkudoktor.loadakkudoktor_year_energy_kwh == 1000
|
||||||
return LoadAkkudoktor()
|
return LoadAkkudoktor()
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@@ -38,10 +36,8 @@ def loadakkudoktoradjusted(config_eos):
|
|||||||
settings = {
|
settings = {
|
||||||
"load": {
|
"load": {
|
||||||
"provider": "LoadAkkudoktorAdjusted",
|
"provider": "LoadAkkudoktorAdjusted",
|
||||||
"provider_settings": {
|
"loadakkudoktor": {
|
||||||
"LoadAkkudoktor": {
|
"loadakkudoktor_year_energy_kwh": "1000",
|
||||||
"loadakkudoktor_year_energy_kwh": "1000",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"measurement": {
|
"measurement": {
|
||||||
@@ -50,7 +46,7 @@ def loadakkudoktoradjusted(config_eos):
|
|||||||
}
|
}
|
||||||
config_eos.merge_settings_from_dict(settings)
|
config_eos.merge_settings_from_dict(settings)
|
||||||
assert config_eos.load.provider == "LoadAkkudoktorAdjusted"
|
assert config_eos.load.provider == "LoadAkkudoktorAdjusted"
|
||||||
assert config_eos.load.provider_settings.LoadAkkudoktor.loadakkudoktor_year_energy_kwh == 1000
|
assert config_eos.load.loadakkudoktor.loadakkudoktor_year_energy_kwh == 1000
|
||||||
return LoadAkkudoktorAdjusted()
|
return LoadAkkudoktorAdjusted()
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
|||||||
@@ -18,12 +18,10 @@ def load_vrm_instance(config_eos):
|
|||||||
settings = {
|
settings = {
|
||||||
"load": {
|
"load": {
|
||||||
"provider": "LoadVrm",
|
"provider": "LoadVrm",
|
||||||
"provider_settings": {
|
"loadvrm": {
|
||||||
"LoadVrm": {
|
"load_vrm_token": "dummy-token",
|
||||||
"load_vrm_token": "dummy-token",
|
"load_vrm_idsite": 12345,
|
||||||
"load_vrm_idsite": 12345,
|
},
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
config_eos.merge_settings_from_dict(settings)
|
config_eos.merge_settings_from_dict(settings)
|
||||||
|
|||||||
6
tests/testdata/eos_config_andreas_now.json
vendored
6
tests/testdata/eos_config_andreas_now.json
vendored
@@ -56,10 +56,8 @@
|
|||||||
"charges_kwh": 0.21
|
"charges_kwh": 0.21
|
||||||
},
|
},
|
||||||
"load": {
|
"load": {
|
||||||
"provider_settings": {
|
"loadakkudoktor": {
|
||||||
"LoadAkkudoktor": {
|
"loadakkudoktor_year_energy_kwh": 13000
|
||||||
"loadakkudoktor_year_energy_kwh": 13000
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pvforecast": {
|
"pvforecast": {
|
||||||
|
|||||||
6
tests/testdata/eosserver_config_1.json
vendored
6
tests/testdata/eosserver_config_1.json
vendored
@@ -13,10 +13,8 @@
|
|||||||
},
|
},
|
||||||
"load": {
|
"load": {
|
||||||
"provider": "LoadImport",
|
"provider": "LoadImport",
|
||||||
"provider_settings": {
|
"loadakkudoktor": {
|
||||||
"LoadAkkudoktor": {
|
"loadakkudoktor_year_energy_kwh": 20000
|
||||||
"loadakkudoktor_year_energy_kwh": 20000
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"optimization": {
|
"optimization": {
|
||||||
|
|||||||
Reference in New Issue
Block a user