mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2025-11-21 04:46:31 +00:00
fix: pydantic extra keywords deprecated (#753)
Pydantic deprecates using extra keyword arguments on Field. Used json_schema_extra instead. Deprecated in Pydantic V2.0 to be removed in V3.0. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
This commit is contained in:
@@ -21,11 +21,11 @@ Properties:
|
|||||||
|
|
||||||
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
| version | `EOS_GENERAL__VERSION` | `str` | `rw` | `0.2.0+dev` | Configuration file version. Used to check compatibility. |
|
| version | `EOS_GENERAL__VERSION` | `str` | `rw` | `0.2.0+dev` | - |
|
||||||
| data_folder_path | `EOS_GENERAL__DATA_FOLDER_PATH` | `Optional[pathlib.Path]` | `rw` | `None` | Path to EOS data directory. |
|
| data_folder_path | `EOS_GENERAL__DATA_FOLDER_PATH` | `Optional[pathlib.Path]` | `rw` | `None` | - |
|
||||||
| data_output_subpath | `EOS_GENERAL__DATA_OUTPUT_SUBPATH` | `Optional[pathlib.Path]` | `rw` | `output` | Sub-path for the EOS output data directory. |
|
| data_output_subpath | `EOS_GENERAL__DATA_OUTPUT_SUBPATH` | `Optional[pathlib.Path]` | `rw` | `output` | - |
|
||||||
| 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` | - |
|
||||||
| 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` | - |
|
||||||
| timezone | | `Optional[str]` | `ro` | `N/A` | Compute timezone based on latitude and longitude. |
|
| timezone | | `Optional[str]` | `ro` | `N/A` | Compute timezone based on latitude and longitude. |
|
||||||
| data_output_path | | `Optional[pathlib.Path]` | `ro` | `N/A` | Compute data_output_path based on data_folder_path. |
|
| data_output_path | | `Optional[pathlib.Path]` | `ro` | `N/A` | Compute data_output_path based on data_folder_path. |
|
||||||
| config_folder_path | | `Optional[pathlib.Path]` | `ro` | `N/A` | Path to EOS configuration directory. |
|
| config_folder_path | | `Optional[pathlib.Path]` | `ro` | `N/A` | Path to EOS configuration directory. |
|
||||||
@@ -76,8 +76,8 @@ Properties:
|
|||||||
|
|
||||||
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
| subpath | `EOS_CACHE__SUBPATH` | `Optional[pathlib.Path]` | `rw` | `cache` | Sub-path for the EOS cache data directory. |
|
| subpath | `EOS_CACHE__SUBPATH` | `Optional[pathlib.Path]` | `rw` | `cache` | - |
|
||||||
| cleanup_interval | `EOS_CACHE__CLEANUP_INTERVAL` | `float` | `rw` | `300` | Intervall in seconds for EOS file cache cleanup. |
|
| cleanup_interval | `EOS_CACHE__CLEANUP_INTERVAL` | `float` | `rw` | `300` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Example Input/Output
|
### Example Input/Output
|
||||||
@@ -101,9 +101,9 @@ Properties:
|
|||||||
|
|
||||||
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
| startup_delay | `EOS_EMS__STARTUP_DELAY` | `float` | `rw` | `5` | Startup delay in seconds for EOS energy management runs. |
|
| startup_delay | `EOS_EMS__STARTUP_DELAY` | `float` | `rw` | `5` | - |
|
||||||
| interval | `EOS_EMS__INTERVAL` | `Optional[float]` | `rw` | `None` | Intervall in seconds between EOS energy management runs. |
|
| interval | `EOS_EMS__INTERVAL` | `Optional[float]` | `rw` | `None` | - |
|
||||||
| mode | `EOS_EMS__MODE` | `Optional[akkudoktoreos.core.emsettings.EnergyManagementMode]` | `rw` | `None` | Energy management mode [OPTIMIZATION | PREDICTION]. |
|
| mode | `EOS_EMS__MODE` | `Optional[akkudoktoreos.core.emsettings.EnergyManagementMode]` | `rw` | `None` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Example Input/Output
|
### Example Input/Output
|
||||||
@@ -128,8 +128,8 @@ Properties:
|
|||||||
|
|
||||||
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
| console_level | `EOS_LOGGING__CONSOLE_LEVEL` | `Optional[str]` | `rw` | `None` | Logging level when logging to console. |
|
| console_level | `EOS_LOGGING__CONSOLE_LEVEL` | `Optional[str]` | `rw` | `None` | - |
|
||||||
| file_level | `EOS_LOGGING__FILE_LEVEL` | `Optional[str]` | `rw` | `None` | Logging level when logging to file. |
|
| file_level | `EOS_LOGGING__FILE_LEVEL` | `Optional[str]` | `rw` | `None` | - |
|
||||||
| file_path | | `Optional[pathlib.Path]` | `ro` | `N/A` | Computed log file path based on data output path. |
|
| file_path | | `Optional[pathlib.Path]` | `ro` | `N/A` | Computed log file path based on data output path. |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
@@ -168,14 +168,14 @@ Properties:
|
|||||||
|
|
||||||
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
| batteries | `EOS_DEVICES__BATTERIES` | `Optional[list[akkudoktoreos.devices.devices.BatteriesCommonSettings]]` | `rw` | `None` | List of battery devices |
|
| batteries | `EOS_DEVICES__BATTERIES` | `Optional[list[akkudoktoreos.devices.devices.BatteriesCommonSettings]]` | `rw` | `None` | - |
|
||||||
| max_batteries | `EOS_DEVICES__MAX_BATTERIES` | `Optional[int]` | `rw` | `None` | Maximum number of batteries that can be set |
|
| max_batteries | `EOS_DEVICES__MAX_BATTERIES` | `Optional[int]` | `rw` | `None` | - |
|
||||||
| electric_vehicles | `EOS_DEVICES__ELECTRIC_VEHICLES` | `Optional[list[akkudoktoreos.devices.devices.BatteriesCommonSettings]]` | `rw` | `None` | List of electric vehicle devices |
|
| electric_vehicles | `EOS_DEVICES__ELECTRIC_VEHICLES` | `Optional[list[akkudoktoreos.devices.devices.BatteriesCommonSettings]]` | `rw` | `None` | - |
|
||||||
| max_electric_vehicles | `EOS_DEVICES__MAX_ELECTRIC_VEHICLES` | `Optional[int]` | `rw` | `None` | Maximum number of electric vehicles that can be set |
|
| max_electric_vehicles | `EOS_DEVICES__MAX_ELECTRIC_VEHICLES` | `Optional[int]` | `rw` | `None` | - |
|
||||||
| inverters | `EOS_DEVICES__INVERTERS` | `Optional[list[akkudoktoreos.devices.devices.InverterCommonSettings]]` | `rw` | `None` | List of inverters |
|
| inverters | `EOS_DEVICES__INVERTERS` | `Optional[list[akkudoktoreos.devices.devices.InverterCommonSettings]]` | `rw` | `None` | - |
|
||||||
| max_inverters | `EOS_DEVICES__MAX_INVERTERS` | `Optional[int]` | `rw` | `None` | Maximum number of inverters that can be set |
|
| max_inverters | `EOS_DEVICES__MAX_INVERTERS` | `Optional[int]` | `rw` | `None` | - |
|
||||||
| home_appliances | `EOS_DEVICES__HOME_APPLIANCES` | `Optional[list[akkudoktoreos.devices.devices.HomeApplianceCommonSettings]]` | `rw` | `None` | List of home appliances |
|
| home_appliances | `EOS_DEVICES__HOME_APPLIANCES` | `Optional[list[akkudoktoreos.devices.devices.HomeApplianceCommonSettings]]` | `rw` | `None` | - |
|
||||||
| max_home_appliances | `EOS_DEVICES__MAX_HOME_APPLIANCES` | `Optional[int]` | `rw` | `None` | Maximum number of home_appliances that can be set |
|
| max_home_appliances | `EOS_DEVICES__MAX_HOME_APPLIANCES` | `Optional[int]` | `rw` | `None` | - |
|
||||||
| measurement_keys | | `Optional[list[str]]` | `ro` | `N/A` | Return the measurement keys for the resource/ device stati that are measurements. |
|
| measurement_keys | | `Optional[list[str]]` | `ro` | `N/A` | Return the measurement keys for the resource/ device stati that are measurements. |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
@@ -337,10 +337,10 @@ Properties:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| device_id | `str` | `rw` | `<unknown>` | ID of device |
|
| device_id | `str` | `rw` | `<unknown>` | - |
|
||||||
| consumption_wh | `int` | `rw` | `required` | Energy consumption [Wh]. |
|
| consumption_wh | `int` | `rw` | `required` | - |
|
||||||
| duration_h | `int` | `rw` | `required` | Usage duration in hours [0 ... 24]. |
|
| duration_h | `int` | `rw` | `required` | - |
|
||||||
| time_windows | `Optional[akkudoktoreos.utils.datetimeutil.TimeWindowSequence]` | `rw` | `None` | Sequence of allowed time windows. Defaults to optimization general time window. |
|
| time_windows | `Optional[akkudoktoreos.utils.datetimeutil.TimeWindowSequence]` | `rw` | `None` | - |
|
||||||
| measurement_keys | `Optional[list[str]]` | `ro` | `N/A` | Measurement keys for the home appliance stati that are measurements. |
|
| measurement_keys | `Optional[list[str]]` | `ro` | `N/A` | Measurement keys for the home appliance stati that are measurements. |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
@@ -367,54 +367,6 @@ Properties:
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "ev1",
|
|
||||||
"consumption_wh": 2000,
|
|
||||||
"duration_h": 1,
|
|
||||||
"time_windows": {
|
|
||||||
"windows": [
|
|
||||||
{
|
|
||||||
"start_time": "10:00:00.000000 Europe/Berlin",
|
|
||||||
"duration": "2 hours",
|
|
||||||
"day_of_week": null,
|
|
||||||
"date": null,
|
|
||||||
"locale": null
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "inverter1",
|
|
||||||
"consumption_wh": 2000,
|
|
||||||
"duration_h": 1,
|
|
||||||
"time_windows": {
|
|
||||||
"windows": [
|
|
||||||
{
|
|
||||||
"start_time": "10:00:00.000000 Europe/Berlin",
|
|
||||||
"duration": "2 hours",
|
|
||||||
"day_of_week": null,
|
|
||||||
"date": null,
|
|
||||||
"locale": null
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "dishwasher",
|
|
||||||
"consumption_wh": 2000,
|
|
||||||
"duration_h": 1,
|
|
||||||
"time_windows": {
|
|
||||||
"windows": [
|
|
||||||
{
|
|
||||||
"start_time": "10:00:00.000000 Europe/Berlin",
|
|
||||||
"duration": "2 hours",
|
|
||||||
"day_of_week": null,
|
|
||||||
"date": null,
|
|
||||||
"locale": null
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -445,57 +397,6 @@ Properties:
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"measurement_keys": []
|
"measurement_keys": []
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "ev1",
|
|
||||||
"consumption_wh": 2000,
|
|
||||||
"duration_h": 1,
|
|
||||||
"time_windows": {
|
|
||||||
"windows": [
|
|
||||||
{
|
|
||||||
"start_time": "10:00:00.000000 Europe/Berlin",
|
|
||||||
"duration": "2 hours",
|
|
||||||
"day_of_week": null,
|
|
||||||
"date": null,
|
|
||||||
"locale": null
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"measurement_keys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "inverter1",
|
|
||||||
"consumption_wh": 2000,
|
|
||||||
"duration_h": 1,
|
|
||||||
"time_windows": {
|
|
||||||
"windows": [
|
|
||||||
{
|
|
||||||
"start_time": "10:00:00.000000 Europe/Berlin",
|
|
||||||
"duration": "2 hours",
|
|
||||||
"day_of_week": null,
|
|
||||||
"date": null,
|
|
||||||
"locale": null
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"measurement_keys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "dishwasher",
|
|
||||||
"consumption_wh": 2000,
|
|
||||||
"duration_h": 1,
|
|
||||||
"time_windows": {
|
|
||||||
"windows": [
|
|
||||||
{
|
|
||||||
"start_time": "10:00:00.000000 Europe/Berlin",
|
|
||||||
"duration": "2 hours",
|
|
||||||
"day_of_week": null,
|
|
||||||
"date": null,
|
|
||||||
"locale": null
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"measurement_keys": []
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -510,9 +411,9 @@ Properties:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| device_id | `str` | `rw` | `<unknown>` | ID of device |
|
| device_id | `str` | `rw` | `<unknown>` | - |
|
||||||
| max_power_w | `Optional[float]` | `rw` | `None` | Maximum power [W]. |
|
| max_power_w | `Optional[float]` | `rw` | `None` | - |
|
||||||
| battery_id | `Optional[str]` | `rw` | `None` | ID of battery controlled by this inverter. |
|
| battery_id | `Optional[str]` | `rw` | `None` | - |
|
||||||
| measurement_keys | `Optional[list[str]]` | `ro` | `N/A` | Measurement keys for the inverter stati that are measurements. |
|
| measurement_keys | `Optional[list[str]]` | `ro` | `N/A` | Measurement keys for the inverter stati that are measurements. |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
@@ -528,21 +429,6 @@ Properties:
|
|||||||
"device_id": "battery1",
|
"device_id": "battery1",
|
||||||
"max_power_w": 10000.0,
|
"max_power_w": 10000.0,
|
||||||
"battery_id": null
|
"battery_id": null
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "ev1",
|
|
||||||
"max_power_w": 10000.0,
|
|
||||||
"battery_id": "battery1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "inverter1",
|
|
||||||
"max_power_w": 10000.0,
|
|
||||||
"battery_id": "battery1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "dishwasher",
|
|
||||||
"max_power_w": 10000.0,
|
|
||||||
"battery_id": "battery1"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -562,24 +448,6 @@ Properties:
|
|||||||
"max_power_w": 10000.0,
|
"max_power_w": 10000.0,
|
||||||
"battery_id": null,
|
"battery_id": null,
|
||||||
"measurement_keys": []
|
"measurement_keys": []
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "ev1",
|
|
||||||
"max_power_w": 10000.0,
|
|
||||||
"battery_id": "battery1",
|
|
||||||
"measurement_keys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "inverter1",
|
|
||||||
"max_power_w": 10000.0,
|
|
||||||
"battery_id": "battery1",
|
|
||||||
"measurement_keys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "dishwasher",
|
|
||||||
"max_power_w": 10000.0,
|
|
||||||
"battery_id": "battery1",
|
|
||||||
"measurement_keys": []
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -594,16 +462,16 @@ Properties:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| device_id | `str` | `rw` | `<unknown>` | ID of device |
|
| device_id | `str` | `rw` | `<unknown>` | - |
|
||||||
| capacity_wh | `int` | `rw` | `8000` | Capacity [Wh]. |
|
| capacity_wh | `int` | `rw` | `8000` | - |
|
||||||
| charging_efficiency | `float` | `rw` | `0.88` | Charging efficiency [0.01 ... 1.00]. |
|
| charging_efficiency | `float` | `rw` | `0.88` | - |
|
||||||
| discharging_efficiency | `float` | `rw` | `0.88` | Discharge efficiency [0.01 ... 1.00]. |
|
| discharging_efficiency | `float` | `rw` | `0.88` | - |
|
||||||
| levelized_cost_of_storage_kwh | `float` | `rw` | `0.0` | Levelized cost of storage (LCOS), the average lifetime cost of delivering one kWh [€/kWh]. |
|
| levelized_cost_of_storage_kwh | `float` | `rw` | `0.0` | - |
|
||||||
| max_charge_power_w | `Optional[float]` | `rw` | `5000` | Maximum charging power [W]. |
|
| max_charge_power_w | `Optional[float]` | `rw` | `5000` | - |
|
||||||
| min_charge_power_w | `Optional[float]` | `rw` | `50` | Minimum charging power [W]. |
|
| min_charge_power_w | `Optional[float]` | `rw` | `50` | - |
|
||||||
| charge_rates | `Optional[numpydantic.vendor.npbase_meta_classes.NDArray]` | `rw` | `[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]` | Charge rates as factor of maximum charging power [0.00 ... 1.00]. None triggers fallback to default charge-rates. |
|
| charge_rates | `Optional[numpydantic.vendor.npbase_meta_classes.NDArray]` | `rw` | `[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]` | - |
|
||||||
| min_soc_percentage | `int` | `rw` | `0` | Minimum state of charge (SOC) as percentage of capacity [%]. This is the target SoC for charging |
|
| min_soc_percentage | `int` | `rw` | `0` | - |
|
||||||
| max_soc_percentage | `int` | `rw` | `100` | Maximum state of charge (SOC) as percentage of capacity [%]. |
|
| max_soc_percentage | `int` | `rw` | `100` | - |
|
||||||
| measurement_key_soc_factor | `str` | `ro` | `N/A` | Measurement key for the battery state of charge (SoC) as factor of total capacity [0.0 ... 1.0]. |
|
| measurement_key_soc_factor | `str` | `ro` | `N/A` | Measurement key for the battery state of charge (SoC) as factor of total capacity [0.0 ... 1.0]. |
|
||||||
| measurement_key_power_l1_w | `str` | `ro` | `N/A` | Measurement key for the L1 power the battery is charged or discharged with [W]. |
|
| measurement_key_power_l1_w | `str` | `ro` | `N/A` | Measurement key for the L1 power the battery is charged or discharged with [W]. |
|
||||||
| measurement_key_power_l2_w | `str` | `ro` | `N/A` | Measurement key for the L2 power the battery is charged or discharged with [W]. |
|
| measurement_key_power_l2_w | `str` | `ro` | `N/A` | Measurement key for the L2 power the battery is charged or discharged with [W]. |
|
||||||
@@ -633,42 +501,6 @@ Battery SoC, power. |
|
|||||||
"charge_rates": "[0. 0.25 0.5 0.75 1. ]",
|
"charge_rates": "[0. 0.25 0.5 0.75 1. ]",
|
||||||
"min_soc_percentage": 10,
|
"min_soc_percentage": 10,
|
||||||
"max_soc_percentage": 100
|
"max_soc_percentage": 100
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "ev1",
|
|
||||||
"capacity_wh": 8000,
|
|
||||||
"charging_efficiency": 0.88,
|
|
||||||
"discharging_efficiency": 0.88,
|
|
||||||
"levelized_cost_of_storage_kwh": 0.12,
|
|
||||||
"max_charge_power_w": 5000.0,
|
|
||||||
"min_charge_power_w": 50.0,
|
|
||||||
"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": 10,
|
|
||||||
"max_soc_percentage": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "inverter1",
|
|
||||||
"capacity_wh": 8000,
|
|
||||||
"charging_efficiency": 0.88,
|
|
||||||
"discharging_efficiency": 0.88,
|
|
||||||
"levelized_cost_of_storage_kwh": 0.12,
|
|
||||||
"max_charge_power_w": 5000.0,
|
|
||||||
"min_charge_power_w": 50.0,
|
|
||||||
"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": 10,
|
|
||||||
"max_soc_percentage": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "dishwasher",
|
|
||||||
"capacity_wh": 8000,
|
|
||||||
"charging_efficiency": 0.88,
|
|
||||||
"discharging_efficiency": 0.88,
|
|
||||||
"levelized_cost_of_storage_kwh": 0.12,
|
|
||||||
"max_charge_power_w": 5000.0,
|
|
||||||
"min_charge_power_w": 50.0,
|
|
||||||
"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": 10,
|
|
||||||
"max_soc_percentage": 100
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -706,78 +538,6 @@ Battery SoC, power. |
|
|||||||
"battery1-power-l3-w",
|
"battery1-power-l3-w",
|
||||||
"battery1-power-3-phase-sym-w"
|
"battery1-power-3-phase-sym-w"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "ev1",
|
|
||||||
"capacity_wh": 8000,
|
|
||||||
"charging_efficiency": 0.88,
|
|
||||||
"discharging_efficiency": 0.88,
|
|
||||||
"levelized_cost_of_storage_kwh": 0.12,
|
|
||||||
"max_charge_power_w": 5000.0,
|
|
||||||
"min_charge_power_w": 50.0,
|
|
||||||
"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": 10,
|
|
||||||
"max_soc_percentage": 100,
|
|
||||||
"measurement_key_soc_factor": "ev1-soc-factor",
|
|
||||||
"measurement_key_power_l1_w": "ev1-power-l1-w",
|
|
||||||
"measurement_key_power_l2_w": "ev1-power-l2-w",
|
|
||||||
"measurement_key_power_l3_w": "ev1-power-l3-w",
|
|
||||||
"measurement_key_power_3_phase_sym_w": "ev1-power-3-phase-sym-w",
|
|
||||||
"measurement_keys": [
|
|
||||||
"ev1-soc-factor",
|
|
||||||
"ev1-power-l1-w",
|
|
||||||
"ev1-power-l2-w",
|
|
||||||
"ev1-power-l3-w",
|
|
||||||
"ev1-power-3-phase-sym-w"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "inverter1",
|
|
||||||
"capacity_wh": 8000,
|
|
||||||
"charging_efficiency": 0.88,
|
|
||||||
"discharging_efficiency": 0.88,
|
|
||||||
"levelized_cost_of_storage_kwh": 0.12,
|
|
||||||
"max_charge_power_w": 5000.0,
|
|
||||||
"min_charge_power_w": 50.0,
|
|
||||||
"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": 10,
|
|
||||||
"max_soc_percentage": 100,
|
|
||||||
"measurement_key_soc_factor": "inverter1-soc-factor",
|
|
||||||
"measurement_key_power_l1_w": "inverter1-power-l1-w",
|
|
||||||
"measurement_key_power_l2_w": "inverter1-power-l2-w",
|
|
||||||
"measurement_key_power_l3_w": "inverter1-power-l3-w",
|
|
||||||
"measurement_key_power_3_phase_sym_w": "inverter1-power-3-phase-sym-w",
|
|
||||||
"measurement_keys": [
|
|
||||||
"inverter1-soc-factor",
|
|
||||||
"inverter1-power-l1-w",
|
|
||||||
"inverter1-power-l2-w",
|
|
||||||
"inverter1-power-l3-w",
|
|
||||||
"inverter1-power-3-phase-sym-w"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"device_id": "dishwasher",
|
|
||||||
"capacity_wh": 8000,
|
|
||||||
"charging_efficiency": 0.88,
|
|
||||||
"discharging_efficiency": 0.88,
|
|
||||||
"levelized_cost_of_storage_kwh": 0.12,
|
|
||||||
"max_charge_power_w": 5000.0,
|
|
||||||
"min_charge_power_w": 50.0,
|
|
||||||
"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": 10,
|
|
||||||
"max_soc_percentage": 100,
|
|
||||||
"measurement_key_soc_factor": "dishwasher-soc-factor",
|
|
||||||
"measurement_key_power_l1_w": "dishwasher-power-l1-w",
|
|
||||||
"measurement_key_power_l2_w": "dishwasher-power-l2-w",
|
|
||||||
"measurement_key_power_l3_w": "dishwasher-power-l3-w",
|
|
||||||
"measurement_key_power_3_phase_sym_w": "dishwasher-power-3-phase-sym-w",
|
|
||||||
"measurement_keys": [
|
|
||||||
"dishwasher-soc-factor",
|
|
||||||
"dishwasher-power-l1-w",
|
|
||||||
"dishwasher-power-l2-w",
|
|
||||||
"dishwasher-power-l3-w",
|
|
||||||
"dishwasher-power-3-phase-sym-w"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -792,10 +552,10 @@ Battery SoC, power. |
|
|||||||
|
|
||||||
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
| load_emr_keys | `EOS_MEASUREMENT__LOAD_EMR_KEYS` | `Optional[list[str]]` | `rw` | `None` | The keys of the measurements that are energy meter readings of a load [kWh]. |
|
| load_emr_keys | `EOS_MEASUREMENT__LOAD_EMR_KEYS` | `Optional[list[str]]` | `rw` | `None` | - |
|
||||||
| grid_export_emr_keys | `EOS_MEASUREMENT__GRID_EXPORT_EMR_KEYS` | `Optional[list[str]]` | `rw` | `None` | The keys of the measurements that are energy meter readings of energy export to grid [kWh]. |
|
| grid_export_emr_keys | `EOS_MEASUREMENT__GRID_EXPORT_EMR_KEYS` | `Optional[list[str]]` | `rw` | `None` | - |
|
||||||
| grid_import_emr_keys | `EOS_MEASUREMENT__GRID_IMPORT_EMR_KEYS` | `Optional[list[str]]` | `rw` | `None` | The keys of the measurements that are energy meter readings of energy import from grid [kWh]. |
|
| grid_import_emr_keys | `EOS_MEASUREMENT__GRID_IMPORT_EMR_KEYS` | `Optional[list[str]]` | `rw` | `None` | - |
|
||||||
| pv_production_emr_keys | `EOS_MEASUREMENT__PV_PRODUCTION_EMR_KEYS` | `Optional[list[str]]` | `rw` | `None` | The keys of the measurements that are PV production energy meter readings [kWh]. |
|
| pv_production_emr_keys | `EOS_MEASUREMENT__PV_PRODUCTION_EMR_KEYS` | `Optional[list[str]]` | `rw` | `None` | - |
|
||||||
| keys | | `list[str]` | `ro` | `N/A` | The keys of the measurements that can be stored. |
|
| keys | | `list[str]` | `ro` | `N/A` | The keys of the measurements that can be stored. |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
@@ -859,10 +619,10 @@ Battery SoC, power. |
|
|||||||
|
|
||||||
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
| horizon_hours | `EOS_OPTIMIZATION__HORIZON_HOURS` | `Optional[int]` | `rw` | `24` | The general time window within which the energy optimization goal shall be achieved [h]. Defaults to 24 hours. |
|
| horizon_hours | `EOS_OPTIMIZATION__HORIZON_HOURS` | `Optional[int]` | `rw` | `24` | - |
|
||||||
| interval | `EOS_OPTIMIZATION__INTERVAL` | `Optional[int]` | `rw` | `3600` | The optimization interval [sec]. |
|
| interval | `EOS_OPTIMIZATION__INTERVAL` | `Optional[int]` | `rw` | `3600` | - |
|
||||||
| algorithm | `EOS_OPTIMIZATION__ALGORITHM` | `Optional[str]` | `rw` | `GENETIC` | The optimization algorithm. |
|
| algorithm | `EOS_OPTIMIZATION__ALGORITHM` | `Optional[str]` | `rw` | `GENETIC` | - |
|
||||||
| genetic | `EOS_OPTIMIZATION__GENETIC` | `Optional[akkudoktoreos.optimization.optimization.GeneticCommonSettings]` | `rw` | `None` | Genetic optimization algorithm configuration. |
|
| genetic | `EOS_OPTIMIZATION__GENETIC` | `Optional[akkudoktoreos.optimization.optimization.GeneticCommonSettings]` | `rw` | `None` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Example Input/Output
|
### Example Input/Output
|
||||||
@@ -895,10 +655,10 @@ Battery SoC, power. |
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| individuals | `Optional[int]` | `rw` | `300` | Number of individuals (solutions) to generate for the (initial) generation [>= 10]. Defaults to 300. |
|
| individuals | `Optional[int]` | `rw` | `300` | - |
|
||||||
| generations | `Optional[int]` | `rw` | `400` | Number of generations to evaluate the optimal solution [>= 10]. Defaults to 400. |
|
| generations | `Optional[int]` | `rw` | `400` | - |
|
||||||
| seed | `Optional[int]` | `rw` | `None` | Fixed seed for genetic algorithm. Defaults to 'None' which means random seed. |
|
| seed | `Optional[int]` | `rw` | `None` | - |
|
||||||
| penalties | `Optional[dict[str, Union[float, int, str]]]` | `rw` | `None` | A dictionary of penalty function parameters consisting of a penalty function parameter name and the associated value. |
|
| penalties | `Optional[dict[str, Union[float, int, str]]]` | `rw` | `None` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Example Input/Output
|
#### Example Input/Output
|
||||||
@@ -942,8 +702,8 @@ Validators:
|
|||||||
|
|
||||||
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
| hours | `EOS_PREDICTION__HOURS` | `Optional[int]` | `rw` | `48` | Number of hours into the future for predictions |
|
| hours | `EOS_PREDICTION__HOURS` | `Optional[int]` | `rw` | `48` | - |
|
||||||
| historic_hours | `EOS_PREDICTION__HISTORIC_HOURS` | `Optional[int]` | `rw` | `48` | Number of hours into the past for historical predictions data |
|
| historic_hours | `EOS_PREDICTION__HISTORIC_HOURS` | `Optional[int]` | `rw` | `48` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Example Input/Output
|
### Example Input/Output
|
||||||
@@ -967,10 +727,10 @@ Validators:
|
|||||||
|
|
||||||
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
| provider | `EOS_ELECPRICE__PROVIDER` | `Optional[str]` | `rw` | `None` | Electricity price provider id of provider to be used. |
|
| provider | `EOS_ELECPRICE__PROVIDER` | `Optional[str]` | `rw` | `None` | - |
|
||||||
| charges_kwh | `EOS_ELECPRICE__CHARGES_KWH` | `Optional[float]` | `rw` | `None` | Electricity price charges [€/kWh]. Will be added to variable market price. |
|
| charges_kwh | `EOS_ELECPRICE__CHARGES_KWH` | `Optional[float]` | `rw` | `None` | - |
|
||||||
| vat_rate | `EOS_ELECPRICE__VAT_RATE` | `Optional[float]` | `rw` | `1.19` | VAT rate factor applied to electricity price when charges are used. |
|
| vat_rate | `EOS_ELECPRICE__VAT_RATE` | `Optional[float]` | `rw` | `1.19` | - |
|
||||||
| provider_settings | `EOS_ELECPRICE__PROVIDER_SETTINGS` | `ElecPriceCommonProviderSettings` | `rw` | `required` | Provider settings |
|
| provider_settings | `EOS_ELECPRICE__PROVIDER_SETTINGS` | `ElecPriceCommonProviderSettings` | `rw` | `required` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Example Input/Output
|
### Example Input/Output
|
||||||
@@ -998,8 +758,8 @@ Validators:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| import_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | Path to the file to import elecprice data from. |
|
| import_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | - |
|
||||||
| import_json | `Optional[str]` | `rw` | `None` | JSON string, dictionary of electricity price forecast value lists. |
|
| import_json | `Optional[str]` | `rw` | `None` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Example Input/Output
|
#### Example Input/Output
|
||||||
@@ -1027,7 +787,7 @@ Validators:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| ElecPriceImport | `Optional[akkudoktoreos.prediction.elecpriceimport.ElecPriceImportCommonSettings]` | `rw` | `None` | ElecPriceImport settings |
|
| ElecPriceImport | `Optional[akkudoktoreos.prediction.elecpriceimport.ElecPriceImportCommonSettings]` | `rw` | `None` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Example Input/Output
|
#### Example Input/Output
|
||||||
@@ -1052,8 +812,8 @@ Validators:
|
|||||||
|
|
||||||
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
| provider | `EOS_FEEDINTARIFF__PROVIDER` | `Optional[str]` | `rw` | `None` | Feed in tariff provider id of provider to be used. |
|
| provider | `EOS_FEEDINTARIFF__PROVIDER` | `Optional[str]` | `rw` | `None` | - |
|
||||||
| provider_settings | `EOS_FEEDINTARIFF__PROVIDER_SETTINGS` | `FeedInTariffCommonProviderSettings` | `rw` | `required` | Provider settings |
|
| provider_settings | `EOS_FEEDINTARIFF__PROVIDER_SETTINGS` | `FeedInTariffCommonProviderSettings` | `rw` | `required` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Example Input/Output
|
### Example Input/Output
|
||||||
@@ -1080,8 +840,8 @@ Validators:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| import_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | Path to the file to import feed in tariff data from. |
|
| import_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | - |
|
||||||
| import_json | `Optional[str]` | `rw` | `None` | JSON string, dictionary of feed in tariff forecast value lists. |
|
| import_json | `Optional[str]` | `rw` | `None` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Example Input/Output
|
#### Example Input/Output
|
||||||
@@ -1109,7 +869,7 @@ Validators:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| feed_in_tariff_kwh | `Optional[float]` | `rw` | `None` | Electricity price feed in tariff [€/kWH]. |
|
| feed_in_tariff_kwh | `Optional[float]` | `rw` | `None` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Example Input/Output
|
#### Example Input/Output
|
||||||
@@ -1136,8 +896,8 @@ Validators:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| FeedInTariffFixed | `Optional[akkudoktoreos.prediction.feedintarifffixed.FeedInTariffFixedCommonSettings]` | `rw` | `None` | FeedInTariffFixed settings |
|
| FeedInTariffFixed | `Optional[akkudoktoreos.prediction.feedintarifffixed.FeedInTariffFixedCommonSettings]` | `rw` | `None` | - |
|
||||||
| FeedInTariffImport | `Optional[akkudoktoreos.prediction.feedintariffimport.FeedInTariffImportCommonSettings]` | `rw` | `None` | FeedInTariffImport settings |
|
| FeedInTariffImport | `Optional[akkudoktoreos.prediction.feedintariffimport.FeedInTariffImportCommonSettings]` | `rw` | `None` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Example Input/Output
|
#### Example Input/Output
|
||||||
@@ -1163,8 +923,8 @@ Validators:
|
|||||||
|
|
||||||
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
| provider | `EOS_LOAD__PROVIDER` | `Optional[str]` | `rw` | `None` | Load provider id of provider to be used. |
|
| provider | `EOS_LOAD__PROVIDER` | `Optional[str]` | `rw` | `None` | - |
|
||||||
| provider_settings | `EOS_LOAD__PROVIDER_SETTINGS` | `LoadCommonProviderSettings` | `rw` | `required` | Provider settings |
|
| provider_settings | `EOS_LOAD__PROVIDER_SETTINGS` | `LoadCommonProviderSettings` | `rw` | `required` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Example Input/Output
|
### Example Input/Output
|
||||||
@@ -1192,8 +952,8 @@ Validators:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| 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_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | - |
|
||||||
| import_json | `Optional[str]` | `rw` | `None` | JSON string, dictionary of load forecast value lists. |
|
| import_json | `Optional[str]` | `rw` | `None` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Example Input/Output
|
#### Example Input/Output
|
||||||
@@ -1221,8 +981,8 @@ Validators:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| load_vrm_token | `str` | `rw` | `your-token` | Token for Connecting VRM API |
|
| load_vrm_token | `str` | `rw` | `your-token` | - |
|
||||||
| load_vrm_idsite | `int` | `rw` | `12345` | VRM-Installation-ID |
|
| load_vrm_idsite | `int` | `rw` | `12345` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Example Input/Output
|
#### Example Input/Output
|
||||||
@@ -1250,7 +1010,7 @@ Validators:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| loadakkudoktor_year_energy_kwh | `Optional[float]` | `rw` | `None` | Yearly energy consumption (kWh). |
|
| loadakkudoktor_year_energy_kwh | `Optional[float]` | `rw` | `None` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Example Input/Output
|
#### Example Input/Output
|
||||||
@@ -1277,9 +1037,9 @@ Validators:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| LoadAkkudoktor | `Optional[akkudoktoreos.prediction.loadakkudoktor.LoadAkkudoktorCommonSettings]` | `rw` | `None` | LoadAkkudoktor settings |
|
| LoadAkkudoktor | `Optional[akkudoktoreos.prediction.loadakkudoktor.LoadAkkudoktorCommonSettings]` | `rw` | `None` | - |
|
||||||
| LoadVrm | `Optional[akkudoktoreos.prediction.loadvrm.LoadVrmCommonSettings]` | `rw` | `None` | LoadVrm settings |
|
| LoadVrm | `Optional[akkudoktoreos.prediction.loadvrm.LoadVrmCommonSettings]` | `rw` | `None` | - |
|
||||||
| LoadImport | `Optional[akkudoktoreos.prediction.loadimport.LoadImportCommonSettings]` | `rw` | `None` | LoadImport settings |
|
| LoadImport | `Optional[akkudoktoreos.prediction.loadimport.LoadImportCommonSettings]` | `rw` | `None` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Example Input/Output
|
#### Example Input/Output
|
||||||
@@ -1306,10 +1066,10 @@ Validators:
|
|||||||
|
|
||||||
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
| provider | `EOS_PVFORECAST__PROVIDER` | `Optional[str]` | `rw` | `None` | PVForecast provider id of provider to be used. |
|
| provider | `EOS_PVFORECAST__PROVIDER` | `Optional[str]` | `rw` | `None` | - |
|
||||||
| provider_settings | `EOS_PVFORECAST__PROVIDER_SETTINGS` | `PVForecastCommonProviderSettings` | `rw` | `required` | Provider settings |
|
| provider_settings | `EOS_PVFORECAST__PROVIDER_SETTINGS` | `PVForecastCommonProviderSettings` | `rw` | `required` | - |
|
||||||
| planes | `EOS_PVFORECAST__PLANES` | `Optional[list[akkudoktoreos.prediction.pvforecast.PVForecastPlaneSetting]]` | `rw` | `None` | Plane configuration. |
|
| planes | `EOS_PVFORECAST__PLANES` | `Optional[list[akkudoktoreos.prediction.pvforecast.PVForecastPlaneSetting]]` | `rw` | `None` | - |
|
||||||
| max_planes | `EOS_PVFORECAST__MAX_PLANES` | `Optional[int]` | `rw` | `0` | Maximum number of planes that can be set |
|
| max_planes | `EOS_PVFORECAST__MAX_PLANES` | `Optional[int]` | `rw` | `0` | - |
|
||||||
| planes_peakpower | | `List[float]` | `ro` | `N/A` | Compute a list of the peak power per active planes. |
|
| planes_peakpower | | `List[float]` | `ro` | `N/A` | Compute a list of the peak power per active planes. |
|
||||||
| planes_azimuth | | `List[float]` | `ro` | `N/A` | Compute a list of the azimuths per active planes. |
|
| planes_azimuth | | `List[float]` | `ro` | `N/A` | Compute a list of the azimuths per active planes. |
|
||||||
| planes_tilt | | `List[float]` | `ro` | `N/A` | Compute a list of the tilts per active planes. |
|
| planes_tilt | | `List[float]` | `ro` | `N/A` | Compute a list of the tilts per active planes. |
|
||||||
@@ -1479,22 +1239,22 @@ Validators:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| surface_tilt | `Optional[float]` | `rw` | `30.0` | Tilt angle from horizontal plane. Ignored for two-axis tracking. |
|
| surface_tilt | `Optional[float]` | `rw` | `30.0` | - |
|
||||||
| surface_azimuth | `Optional[float]` | `rw` | `180.0` | Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270). |
|
| surface_azimuth | `Optional[float]` | `rw` | `180.0` | - |
|
||||||
| userhorizon | `Optional[List[float]]` | `rw` | `None` | Elevation of horizon in degrees, at equally spaced azimuth clockwise from north. |
|
| userhorizon | `Optional[List[float]]` | `rw` | `None` | - |
|
||||||
| peakpower | `Optional[float]` | `rw` | `None` | Nominal power of PV system in kW. |
|
| peakpower | `Optional[float]` | `rw` | `None` | - |
|
||||||
| pvtechchoice | `Optional[str]` | `rw` | `crystSi` | PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'. |
|
| pvtechchoice | `Optional[str]` | `rw` | `crystSi` | - |
|
||||||
| mountingplace | `Optional[str]` | `rw` | `free` | Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated. |
|
| mountingplace | `Optional[str]` | `rw` | `free` | - |
|
||||||
| loss | `Optional[float]` | `rw` | `14.0` | Sum of PV system losses in percent |
|
| loss | `Optional[float]` | `rw` | `14.0` | - |
|
||||||
| trackingtype | `Optional[int]` | `rw` | `None` | Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south. |
|
| trackingtype | `Optional[int]` | `rw` | `None` | - |
|
||||||
| optimal_surface_tilt | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt angle. Ignored for two-axis tracking. |
|
| optimal_surface_tilt | `Optional[bool]` | `rw` | `False` | - |
|
||||||
| optimalangles | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking. |
|
| optimalangles | `Optional[bool]` | `rw` | `False` | - |
|
||||||
| albedo | `Optional[float]` | `rw` | `None` | Proportion of the light hitting the ground that it reflects back. |
|
| albedo | `Optional[float]` | `rw` | `None` | - |
|
||||||
| module_model | `Optional[str]` | `rw` | `None` | Model of the PV modules of this plane. |
|
| module_model | `Optional[str]` | `rw` | `None` | - |
|
||||||
| inverter_model | `Optional[str]` | `rw` | `None` | Model of the inverter of this plane. |
|
| inverter_model | `Optional[str]` | `rw` | `None` | - |
|
||||||
| inverter_paco | `Optional[int]` | `rw` | `None` | AC power rating of the inverter [W]. |
|
| inverter_paco | `Optional[int]` | `rw` | `None` | - |
|
||||||
| modules_per_string | `Optional[int]` | `rw` | `None` | Number of the PV modules of the strings of this plane. |
|
| modules_per_string | `Optional[int]` | `rw` | `None` | - |
|
||||||
| strings_per_inverter | `Optional[int]` | `rw` | `None` | Number of the strings of the inverter of this plane. |
|
| strings_per_inverter | `Optional[int]` | `rw` | `None` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Example Input/Output
|
#### Example Input/Output
|
||||||
@@ -1526,28 +1286,6 @@ Validators:
|
|||||||
"inverter_paco": 6000,
|
"inverter_paco": 6000,
|
||||||
"modules_per_string": 20,
|
"modules_per_string": 20,
|
||||||
"strings_per_inverter": 2
|
"strings_per_inverter": 2
|
||||||
},
|
|
||||||
{
|
|
||||||
"surface_tilt": 20.0,
|
|
||||||
"surface_azimuth": 90.0,
|
|
||||||
"userhorizon": [
|
|
||||||
5.0,
|
|
||||||
15.0,
|
|
||||||
25.0
|
|
||||||
],
|
|
||||||
"peakpower": 3.5,
|
|
||||||
"pvtechchoice": "crystSi",
|
|
||||||
"mountingplace": "free",
|
|
||||||
"loss": 14.0,
|
|
||||||
"trackingtype": 1,
|
|
||||||
"optimal_surface_tilt": false,
|
|
||||||
"optimalangles": false,
|
|
||||||
"albedo": null,
|
|
||||||
"module_model": null,
|
|
||||||
"inverter_model": null,
|
|
||||||
"inverter_paco": 4000,
|
|
||||||
"modules_per_string": 20,
|
|
||||||
"strings_per_inverter": 2
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1562,8 +1300,8 @@ Validators:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| pvforecast_vrm_token | `str` | `rw` | `your-token` | Token for Connecting VRM API |
|
| pvforecast_vrm_token | `str` | `rw` | `your-token` | - |
|
||||||
| pvforecast_vrm_idsite | `int` | `rw` | `12345` | VRM-Installation-ID |
|
| pvforecast_vrm_idsite | `int` | `rw` | `12345` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Example Input/Output
|
#### Example Input/Output
|
||||||
@@ -1591,8 +1329,8 @@ Validators:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| import_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | Path to the file to import PV forecast data from. |
|
| import_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | - |
|
||||||
| import_json | `Optional[str]` | `rw` | `None` | JSON string, dictionary of PV forecast value lists. |
|
| import_json | `Optional[str]` | `rw` | `None` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Example Input/Output
|
#### Example Input/Output
|
||||||
@@ -1620,8 +1358,8 @@ Validators:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| PVForecastImport | `Optional[akkudoktoreos.prediction.pvforecastimport.PVForecastImportCommonSettings]` | `rw` | `None` | PVForecastImport settings |
|
| PVForecastImport | `Optional[akkudoktoreos.prediction.pvforecastimport.PVForecastImportCommonSettings]` | `rw` | `None` | - |
|
||||||
| PVForecastVrm | `Optional[akkudoktoreos.prediction.pvforecastvrm.PVForecastVrmCommonSettings]` | `rw` | `None` | PVForecastVrm settings |
|
| PVForecastVrm | `Optional[akkudoktoreos.prediction.pvforecastvrm.PVForecastVrmCommonSettings]` | `rw` | `None` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Example Input/Output
|
#### Example Input/Output
|
||||||
@@ -1647,8 +1385,8 @@ Validators:
|
|||||||
|
|
||||||
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
| provider | `EOS_WEATHER__PROVIDER` | `Optional[str]` | `rw` | `None` | Weather provider id of provider to be used. |
|
| provider | `EOS_WEATHER__PROVIDER` | `Optional[str]` | `rw` | `None` | - |
|
||||||
| provider_settings | `EOS_WEATHER__PROVIDER_SETTINGS` | `WeatherCommonProviderSettings` | `rw` | `required` | Provider settings |
|
| provider_settings | `EOS_WEATHER__PROVIDER_SETTINGS` | `WeatherCommonProviderSettings` | `rw` | `required` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Example Input/Output
|
### Example Input/Output
|
||||||
@@ -1674,8 +1412,8 @@ Validators:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| import_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | Path to the file to import weather data from. |
|
| import_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | - |
|
||||||
| import_json | `Optional[str]` | `rw` | `None` | JSON string, dictionary of weather forecast value lists. |
|
| import_json | `Optional[str]` | `rw` | `None` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Example Input/Output
|
#### Example Input/Output
|
||||||
@@ -1703,7 +1441,7 @@ Validators:
|
|||||||
|
|
||||||
| Name | Type | Read-Only | Default | Description |
|
| Name | Type | Read-Only | Default | Description |
|
||||||
| ---- | ---- | --------- | ------- | ----------- |
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
| WeatherImport | `Optional[akkudoktoreos.prediction.weatherimport.WeatherImportCommonSettings]` | `rw` | `None` | WeatherImport settings |
|
| WeatherImport | `Optional[akkudoktoreos.prediction.weatherimport.WeatherImportCommonSettings]` | `rw` | `None` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Example Input/Output
|
#### Example Input/Output
|
||||||
@@ -1728,12 +1466,12 @@ Validators:
|
|||||||
|
|
||||||
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
| host | `EOS_SERVER__HOST` | `Optional[str]` | `rw` | `127.0.0.1` | EOS server IP address. Defaults to 127.0.0.1. |
|
| host | `EOS_SERVER__HOST` | `Optional[str]` | `rw` | `127.0.0.1` | - |
|
||||||
| port | `EOS_SERVER__PORT` | `Optional[int]` | `rw` | `8503` | EOS server IP port number. Defaults to 8503. |
|
| port | `EOS_SERVER__PORT` | `Optional[int]` | `rw` | `8503` | - |
|
||||||
| verbose | `EOS_SERVER__VERBOSE` | `Optional[bool]` | `rw` | `False` | Enable debug output |
|
| verbose | `EOS_SERVER__VERBOSE` | `Optional[bool]` | `rw` | `False` | - |
|
||||||
| startup_eosdash | `EOS_SERVER__STARTUP_EOSDASH` | `Optional[bool]` | `rw` | `True` | EOS server to start EOSdash server. Defaults to True. |
|
| startup_eosdash | `EOS_SERVER__STARTUP_EOSDASH` | `Optional[bool]` | `rw` | `True` | - |
|
||||||
| eosdash_host | `EOS_SERVER__EOSDASH_HOST` | `Optional[str]` | `rw` | `None` | EOSdash server IP address. Defaults to EOS server IP address. |
|
| eosdash_host | `EOS_SERVER__EOSDASH_HOST` | `Optional[str]` | `rw` | `None` | - |
|
||||||
| eosdash_port | `EOS_SERVER__EOSDASH_PORT` | `Optional[int]` | `rw` | `None` | EOSdash server IP port number. Defaults to EOS server IP port number + 1. |
|
| eosdash_port | `EOS_SERVER__EOSDASH_PORT` | `Optional[int]` | `rw` | `None` | - |
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Example Input/Output
|
### Example Input/Output
|
||||||
|
|||||||
@@ -53,17 +53,49 @@ def resolve_nested_types(field_type: Any, parent_types: list[str]) -> list[tuple
|
|||||||
|
|
||||||
|
|
||||||
def get_example_or_default(field_name: str, field_info: FieldInfo, example_ix: int) -> Any:
|
def get_example_or_default(field_name: str, field_info: FieldInfo, example_ix: int) -> Any:
|
||||||
"""Generate a default value for a field, considering constraints."""
|
"""Generate a default value for a field, considering constraints.
|
||||||
if field_info.examples is not None:
|
|
||||||
try:
|
|
||||||
return field_info.examples[example_ix]
|
|
||||||
except IndexError:
|
|
||||||
return field_info.examples[-1]
|
|
||||||
|
|
||||||
if field_info.default is not None:
|
Priority:
|
||||||
|
1. field_info.examples
|
||||||
|
2. field_info.example
|
||||||
|
3. json_schema_extra['examples']
|
||||||
|
4. json_schema_extra['example']
|
||||||
|
5. field_info.default
|
||||||
|
"""
|
||||||
|
# 1. Old-style examples attribute
|
||||||
|
examples = getattr(field_info, "examples", None)
|
||||||
|
if examples is not None:
|
||||||
|
try:
|
||||||
|
return examples[example_ix]
|
||||||
|
except IndexError:
|
||||||
|
return examples[-1]
|
||||||
|
|
||||||
|
# 2. Old-style single example
|
||||||
|
example = getattr(field_info, "example", None)
|
||||||
|
if example is not None:
|
||||||
|
return example
|
||||||
|
|
||||||
|
# 3. Look into json_schema_extra (new style)
|
||||||
|
extra = getattr(field_info, "json_schema_extra", {}) or {}
|
||||||
|
|
||||||
|
examples = extra.get("examples")
|
||||||
|
if examples is not None:
|
||||||
|
try:
|
||||||
|
return examples[example_ix]
|
||||||
|
except IndexError:
|
||||||
|
return examples[-1]
|
||||||
|
|
||||||
|
example = extra.get("example")
|
||||||
|
if example is not None:
|
||||||
|
return example
|
||||||
|
|
||||||
|
# 5. Default
|
||||||
|
if getattr(field_info, "default", None) not in (None, ...):
|
||||||
return field_info.default
|
return field_info.default
|
||||||
|
|
||||||
raise NotImplementedError(f"No default or example provided '{field_name}': {field_info}")
|
raise NotImplementedError(
|
||||||
|
f"No default or example provided for field '{field_name}': {field_info}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_model_structure_from_examples(
|
def get_model_structure_from_examples(
|
||||||
|
|||||||
@@ -85,28 +85,38 @@ class GeneralSettings(SettingsBaseModel):
|
|||||||
_config_file_path: ClassVar[Optional[Path]] = None
|
_config_file_path: ClassVar[Optional[Path]] = None
|
||||||
|
|
||||||
version: str = Field(
|
version: str = Field(
|
||||||
default=__version__, description="Configuration file version. Used to check compatibility."
|
default=__version__,
|
||||||
|
json_schema_extra={
|
||||||
|
"description": "Configuration file version. Used to check compatibility."
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
data_folder_path: Optional[Path] = Field(
|
data_folder_path: Optional[Path] = Field(
|
||||||
default=None, description="Path to EOS data directory.", examples=[None, "/home/eos/data"]
|
default=None,
|
||||||
|
json_schema_extra={
|
||||||
|
"description": "Path to EOS data directory.",
|
||||||
|
"examples": [None, "/home/eos/data"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
data_output_subpath: Optional[Path] = Field(
|
data_output_subpath: Optional[Path] = Field(
|
||||||
default="output", description="Sub-path for the EOS output data directory."
|
default="output",
|
||||||
|
json_schema_extra={"description": "Sub-path for the EOS output data directory."},
|
||||||
)
|
)
|
||||||
|
|
||||||
latitude: Optional[float] = Field(
|
latitude: Optional[float] = Field(
|
||||||
default=52.52,
|
default=52.52,
|
||||||
ge=-90.0,
|
ge=-90.0,
|
||||||
le=90.0,
|
le=90.0,
|
||||||
description="Latitude in decimal degrees, between -90 and 90, north is positive (ISO 19115) (°)",
|
json_schema_extra={
|
||||||
|
"description": "Latitude in decimal degrees, between -90 and 90, north is positive (ISO 19115) (°)"
|
||||||
|
},
|
||||||
)
|
)
|
||||||
longitude: Optional[float] = Field(
|
longitude: Optional[float] = Field(
|
||||||
default=13.405,
|
default=13.405,
|
||||||
ge=-180.0,
|
ge=-180.0,
|
||||||
le=180.0,
|
le=180.0,
|
||||||
description="Longitude in decimal degrees, within -180 to 180 (°)",
|
json_schema_extra={"description": "Longitude in decimal degrees, within -180 to 180 (°)"},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Computed fields
|
# Computed fields
|
||||||
@@ -158,64 +168,49 @@ class SettingsEOS(pydantic_settings.BaseSettings, PydanticModelNestedValueMixin)
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
general: Optional[GeneralSettings] = Field(
|
general: Optional[GeneralSettings] = Field(
|
||||||
default=None,
|
default=None, json_schema_extra={"description": "General Settings"}
|
||||||
description="General Settings",
|
|
||||||
)
|
)
|
||||||
cache: Optional[CacheCommonSettings] = Field(
|
cache: Optional[CacheCommonSettings] = Field(
|
||||||
default=None,
|
default=None, json_schema_extra={"description": "Cache Settings"}
|
||||||
description="Cache Settings",
|
|
||||||
)
|
)
|
||||||
ems: Optional[EnergyManagementCommonSettings] = Field(
|
ems: Optional[EnergyManagementCommonSettings] = Field(
|
||||||
default=None,
|
default=None, json_schema_extra={"description": "Energy Management Settings"}
|
||||||
description="Energy Management Settings",
|
|
||||||
)
|
)
|
||||||
logging: Optional[LoggingCommonSettings] = Field(
|
logging: Optional[LoggingCommonSettings] = Field(
|
||||||
default=None,
|
default=None, json_schema_extra={"description": "Logging Settings"}
|
||||||
description="Logging Settings",
|
|
||||||
)
|
)
|
||||||
devices: Optional[DevicesCommonSettings] = Field(
|
devices: Optional[DevicesCommonSettings] = Field(
|
||||||
default=None,
|
default=None, json_schema_extra={"description": "Devices Settings"}
|
||||||
description="Devices Settings",
|
|
||||||
)
|
)
|
||||||
measurement: Optional[MeasurementCommonSettings] = Field(
|
measurement: Optional[MeasurementCommonSettings] = Field(
|
||||||
default=None,
|
default=None, json_schema_extra={"description": "Measurement Settings"}
|
||||||
description="Measurement Settings",
|
|
||||||
)
|
)
|
||||||
optimization: Optional[OptimizationCommonSettings] = Field(
|
optimization: Optional[OptimizationCommonSettings] = Field(
|
||||||
default=None,
|
default=None, json_schema_extra={"description": "Optimization Settings"}
|
||||||
description="Optimization Settings",
|
|
||||||
)
|
)
|
||||||
prediction: Optional[PredictionCommonSettings] = Field(
|
prediction: Optional[PredictionCommonSettings] = Field(
|
||||||
default=None,
|
default=None, json_schema_extra={"description": "Prediction Settings"}
|
||||||
description="Prediction Settings",
|
|
||||||
)
|
)
|
||||||
elecprice: Optional[ElecPriceCommonSettings] = Field(
|
elecprice: Optional[ElecPriceCommonSettings] = Field(
|
||||||
default=None,
|
default=None, json_schema_extra={"description": "Electricity Price Settings"}
|
||||||
description="Electricity Price Settings",
|
|
||||||
)
|
)
|
||||||
feedintariff: Optional[FeedInTariffCommonSettings] = Field(
|
feedintariff: Optional[FeedInTariffCommonSettings] = Field(
|
||||||
default=None,
|
default=None, json_schema_extra={"description": "Feed In Tariff Settings"}
|
||||||
description="Feed In Tariff Settings",
|
|
||||||
)
|
)
|
||||||
load: Optional[LoadCommonSettings] = Field(
|
load: Optional[LoadCommonSettings] = Field(
|
||||||
default=None,
|
default=None, json_schema_extra={"description": "Load Settings"}
|
||||||
description="Load Settings",
|
|
||||||
)
|
)
|
||||||
pvforecast: Optional[PVForecastCommonSettings] = Field(
|
pvforecast: Optional[PVForecastCommonSettings] = Field(
|
||||||
default=None,
|
default=None, json_schema_extra={"description": "PV Forecast Settings"}
|
||||||
description="PV Forecast Settings",
|
|
||||||
)
|
)
|
||||||
weather: Optional[WeatherCommonSettings] = Field(
|
weather: Optional[WeatherCommonSettings] = Field(
|
||||||
default=None,
|
default=None, json_schema_extra={"description": "Weather Settings"}
|
||||||
description="Weather Settings",
|
|
||||||
)
|
)
|
||||||
server: Optional[ServerCommonSettings] = Field(
|
server: Optional[ServerCommonSettings] = Field(
|
||||||
default=None,
|
default=None, json_schema_extra={"description": "Server Settings"}
|
||||||
description="Server Settings",
|
|
||||||
)
|
)
|
||||||
utils: Optional[UtilsCommonSettings] = Field(
|
utils: Optional[UtilsCommonSettings] = Field(
|
||||||
default=None,
|
default=None, json_schema_extra={"description": "Utilities Settings"}
|
||||||
description="Utilities Settings",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
model_config = pydantic_settings.SettingsConfigDict(
|
model_config = pydantic_settings.SettingsConfigDict(
|
||||||
|
|||||||
@@ -251,10 +251,14 @@ RetType = TypeVar("RetType")
|
|||||||
|
|
||||||
|
|
||||||
class CacheFileRecord(PydanticBaseModel):
|
class CacheFileRecord(PydanticBaseModel):
|
||||||
cache_file: Any = Field(..., description="File descriptor of the cache file.")
|
cache_file: Any = Field(
|
||||||
until_datetime: DateTime = Field(..., description="Datetime until the cache file is valid.")
|
..., json_schema_extra={"description": "File descriptor of the cache file."}
|
||||||
|
)
|
||||||
|
until_datetime: DateTime = Field(
|
||||||
|
..., json_schema_extra={"description": "Datetime until the cache file is valid."}
|
||||||
|
)
|
||||||
ttl_duration: Optional[Duration] = Field(
|
ttl_duration: Optional[Duration] = Field(
|
||||||
default=None, description="Duration the cache file is valid."
|
default=None, json_schema_extra={"description": "Duration the cache file is valid."}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,13 @@ class CacheCommonSettings(SettingsBaseModel):
|
|||||||
"""Cache Configuration."""
|
"""Cache Configuration."""
|
||||||
|
|
||||||
subpath: Optional[Path] = Field(
|
subpath: Optional[Path] = Field(
|
||||||
default="cache", description="Sub-path for the EOS cache data directory."
|
default="cache",
|
||||||
|
json_schema_extra={"description": "Sub-path for the EOS cache data directory."},
|
||||||
)
|
)
|
||||||
|
|
||||||
cleanup_interval: float = Field(
|
cleanup_interval: float = Field(
|
||||||
default=5 * 60, description="Intervall in seconds for EOS file cache cleanup."
|
default=5 * 60,
|
||||||
|
json_schema_extra={"description": "Intervall in seconds for EOS file cache cleanup."},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Do not make this a pydantic computed field. The pydantic model must be fully initialized
|
# Do not make this a pydantic computed field. The pydantic model must be fully initialized
|
||||||
|
|||||||
@@ -84,12 +84,16 @@ class DataRecord(DataBase, MutableMapping):
|
|||||||
- Supports non-standard data types like `datetime`.
|
- Supports non-standard data types like `datetime`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
date_time: Optional[DateTime] = Field(default=None, description="DateTime")
|
date_time: Optional[DateTime] = Field(
|
||||||
|
default=None, json_schema_extra={"description": "DateTime"}
|
||||||
|
)
|
||||||
|
|
||||||
configured_data: dict[str, Any] = Field(
|
configured_data: dict[str, Any] = Field(
|
||||||
default_factory=dict,
|
default_factory=dict,
|
||||||
description="Configured field like data",
|
json_schema_extra={
|
||||||
examples=[{"load0_mr": 40421}],
|
"description": "Configured field like data",
|
||||||
|
"examples": [{"load0_mr": 40421}],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Pydantic v2 model configuration
|
# Pydantic v2 model configuration
|
||||||
@@ -368,10 +372,11 @@ class DataRecord(DataBase, MutableMapping):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
# Get all descriptions from the fields
|
# Get all descriptions from the fields
|
||||||
descriptions = {
|
descriptions: dict[str, str] = {}
|
||||||
field_name: field_info.description
|
for field_name in cls.model_fields.keys():
|
||||||
for field_name, field_info in cls.model_fields.items()
|
desc = cls.field_description(field_name)
|
||||||
}
|
if desc:
|
||||||
|
descriptions[field_name] = desc
|
||||||
|
|
||||||
# Use difflib to get close matches
|
# Use difflib to get close matches
|
||||||
matches = difflib.get_close_matches(
|
matches = difflib.get_close_matches(
|
||||||
@@ -429,8 +434,7 @@ class DataSequence(DataBase, MutableSequence):
|
|||||||
Usage:
|
Usage:
|
||||||
# Example of creating, adding, and using DataSequence
|
# Example of creating, adding, and using DataSequence
|
||||||
class DerivedSequence(DataSquence):
|
class DerivedSequence(DataSquence):
|
||||||
records: List[DerivedDataRecord] = Field(default_factory=list,
|
records: List[DerivedDataRecord] = Field(default_factory=list, json_schema_extra={ "description": "List of data records" })
|
||||||
description="List of data records")
|
|
||||||
|
|
||||||
seq = DerivedSequence()
|
seq = DerivedSequence()
|
||||||
seq.insert(DerivedDataRecord(date_time=datetime.now(), temperature=72))
|
seq.insert(DerivedDataRecord(date_time=datetime.now(), temperature=72))
|
||||||
@@ -445,7 +449,9 @@ class DataSequence(DataBase, MutableSequence):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# To be overloaded by derived classes.
|
# To be overloaded by derived classes.
|
||||||
records: List[DataRecord] = Field(default_factory=list, description="List of data records")
|
records: List[DataRecord] = Field(
|
||||||
|
default_factory=list, json_schema_extra={"description": "List of data records"}
|
||||||
|
)
|
||||||
|
|
||||||
# Derived fields (computed)
|
# Derived fields (computed)
|
||||||
@computed_field # type: ignore[prop-decorator]
|
@computed_field # type: ignore[prop-decorator]
|
||||||
@@ -1313,7 +1319,7 @@ class DataProvider(SingletonMixin, DataSequence):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
update_datetime: Optional[AwareDatetime] = Field(
|
update_datetime: Optional[AwareDatetime] = Field(
|
||||||
None, description="Latest update datetime for generic data"
|
None, json_schema_extra={"description": "Latest update datetime for generic data"}
|
||||||
)
|
)
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@@ -1780,7 +1786,7 @@ class DataContainer(SingletonMixin, DataBase, MutableMapping):
|
|||||||
|
|
||||||
# To be overloaded by derived classes.
|
# To be overloaded by derived classes.
|
||||||
providers: List[DataProvider] = Field(
|
providers: List[DataProvider] = Field(
|
||||||
default_factory=list, description="List of data providers"
|
default_factory=list, json_schema_extra={"description": "List of data providers"}
|
||||||
)
|
)
|
||||||
|
|
||||||
@field_validator("providers", mode="after")
|
@field_validator("providers", mode="after")
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -24,17 +24,23 @@ class EnergyManagementCommonSettings(SettingsBaseModel):
|
|||||||
startup_delay: float = Field(
|
startup_delay: float = Field(
|
||||||
default=5,
|
default=5,
|
||||||
ge=1,
|
ge=1,
|
||||||
description="Startup delay in seconds for EOS energy management runs.",
|
json_schema_extra={
|
||||||
|
"description": "Startup delay in seconds for EOS energy management runs."
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
interval: Optional[float] = Field(
|
interval: Optional[float] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Intervall in seconds between EOS energy management runs.",
|
json_schema_extra={
|
||||||
examples=["300"],
|
"description": "Intervall in seconds between EOS energy management runs.",
|
||||||
|
"examples": ["300"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
mode: Optional[EnergyManagementMode] = Field(
|
mode: Optional[EnergyManagementMode] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Energy management mode [OPTIMIZATION | PREDICTION].",
|
json_schema_extra={
|
||||||
examples=["OPTIMIZATION", "PREDICTION"],
|
"description": "Energy management mode [OPTIMIZATION | PREDICTION].",
|
||||||
|
"examples": ["OPTIMIZATION", "PREDICTION"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,14 +17,18 @@ class LoggingCommonSettings(SettingsBaseModel):
|
|||||||
|
|
||||||
console_level: Optional[str] = Field(
|
console_level: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Logging level when logging to console.",
|
json_schema_extra={
|
||||||
examples=LOGGING_LEVELS,
|
"description": "Logging level when logging to console.",
|
||||||
|
"examples": LOGGING_LEVELS,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
file_level: Optional[str] = Field(
|
file_level: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Logging level when logging to file.",
|
json_schema_extra={
|
||||||
examples=LOGGING_LEVELS,
|
"description": "Logging level when logging to file.",
|
||||||
|
"examples": LOGGING_LEVELS,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@computed_field # type: ignore[prop-decorator]
|
@computed_field # type: ignore[prop-decorator]
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ from pydantic import (
|
|||||||
ValidationInfo,
|
ValidationInfo,
|
||||||
field_validator,
|
field_validator,
|
||||||
)
|
)
|
||||||
|
from pydantic.fields import ComputedFieldInfo, FieldInfo
|
||||||
|
|
||||||
from akkudoktoreos.utils.datetimeutil import DateTime, to_datetime, to_duration
|
from akkudoktoreos.utils.datetimeutil import DateTime, to_datetime, to_duration
|
||||||
|
|
||||||
@@ -720,6 +721,146 @@ class PydanticBaseModel(PydanticModelNestedValueMixin, BaseModel):
|
|||||||
data = json.loads(json_str)
|
data = json.loads(json_str)
|
||||||
return cls.model_validate(data)
|
return cls.model_validate(data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _field_extra_dict(
|
||||||
|
cls,
|
||||||
|
model_field: Union[FieldInfo, ComputedFieldInfo],
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""Return the ``json_schema_extra`` dictionary for a given model field.
|
||||||
|
|
||||||
|
This method provides a safe and unified way to access the
|
||||||
|
``json_schema_extra`` metadata associated with a Pydantic field
|
||||||
|
definition. It supports both standard fields defined via
|
||||||
|
``Field(...)`` and computed fields, and gracefully handles
|
||||||
|
cases where ``json_schema_extra`` is not present.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
model_field (Union[FieldInfo, ComputedFieldInfo]):
|
||||||
|
The Pydantic field object from which to extract
|
||||||
|
``json_schema_extra`` metadata. This can be obtained
|
||||||
|
from ``model.model_fields[field_name]`` or
|
||||||
|
``model.model_computed_fields[field_name]``.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[str, Any]:
|
||||||
|
A dictionary containing the field’s ``json_schema_extra``
|
||||||
|
metadata. If no metadata is available, an empty dictionary
|
||||||
|
is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
None:
|
||||||
|
This method does not raise. Missing metadata is handled
|
||||||
|
gracefully by returning an empty dictionary.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
>>> class User(Base):
|
||||||
|
... name: str = Field(
|
||||||
|
... json_schema_extra={"description": "User name"}
|
||||||
|
... )
|
||||||
|
...
|
||||||
|
>>> field = User.model_fields["name"]
|
||||||
|
>>> User.get_field_extra_dict(field)
|
||||||
|
{'description': 'User name'}
|
||||||
|
|
||||||
|
>>> missing = User.model_fields.get("unknown", None)
|
||||||
|
>>> User.get_field_extra_dict(missing) if missing else {}
|
||||||
|
{}
|
||||||
|
"""
|
||||||
|
if model_field is None:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
# Pydantic v2 primary location
|
||||||
|
extra = getattr(model_field, "json_schema_extra", None)
|
||||||
|
if isinstance(extra, dict):
|
||||||
|
return extra
|
||||||
|
|
||||||
|
# Pydantic v1 compatibility fallback
|
||||||
|
fi = getattr(model_field, "field_info", None)
|
||||||
|
if fi is not None:
|
||||||
|
extra = getattr(fi, "json_schema_extra", None)
|
||||||
|
if isinstance(extra, dict):
|
||||||
|
return extra
|
||||||
|
|
||||||
|
return {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def field_description(cls, field_name: str) -> Optional[str]:
|
||||||
|
"""Return the description metadata of a model field, if available.
|
||||||
|
|
||||||
|
This method retrieves the `Field` specification from the model's
|
||||||
|
`model_fields` registry and extracts its description from the field's
|
||||||
|
`json_schema_extra` / `extra` metadata (as provided by
|
||||||
|
`_field_extra_dict`). If the field does not exist or no description is
|
||||||
|
present, ``None`` is returned.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
field_name (str):
|
||||||
|
Name of the field whose description should be returned.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Optional[str]:
|
||||||
|
The textual description if present, otherwise ``None``.
|
||||||
|
"""
|
||||||
|
field = cls.model_fields.get(field_name)
|
||||||
|
if not field:
|
||||||
|
return None
|
||||||
|
extra = cls._field_extra_dict(field)
|
||||||
|
if "description" in extra:
|
||||||
|
return str(extra["description"])
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def field_deprecated(cls, field_name: str) -> Optional[str]:
|
||||||
|
"""Return the deprecated metadata of a model field, if available.
|
||||||
|
|
||||||
|
This method retrieves the `Field` specification from the model's
|
||||||
|
`model_fields` registry and extracts its description from the field's
|
||||||
|
`json_schema_extra` / `extra` metadata (as provided by
|
||||||
|
`_field_extra_dict`). If the field does not exist or no description is
|
||||||
|
present, ``None`` is returned.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
field_name (str):
|
||||||
|
Name of the field whose deprecated info should be returned.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Optional[str]:
|
||||||
|
The textual deprecated info if present, otherwise ``None``.
|
||||||
|
"""
|
||||||
|
field = cls.model_fields.get(field_name)
|
||||||
|
if not field:
|
||||||
|
return None
|
||||||
|
extra = cls._field_extra_dict(field)
|
||||||
|
if "deprecated" in extra:
|
||||||
|
return str(extra["deprecated"])
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def field_examples(cls, field_name: str) -> Optional[list[Any]]:
|
||||||
|
"""Return the examples metadata of a model field, if available.
|
||||||
|
|
||||||
|
This method retrieves the `Field` specification from the model's
|
||||||
|
`model_fields` registry and extracts its description from the field's
|
||||||
|
`json_schema_extra` / `extra` metadata (as provided by
|
||||||
|
`_field_extra_dict`). If the field does not exist or no description is
|
||||||
|
present, ``None`` is returned.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
field_name (str):
|
||||||
|
Name of the field whose examples should be returned.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Optional[list[Any]]:
|
||||||
|
The examples if present, otherwise ``None``.
|
||||||
|
"""
|
||||||
|
field = cls.model_fields.get(field_name)
|
||||||
|
if not field:
|
||||||
|
return None
|
||||||
|
extra = cls._field_extra_dict(field)
|
||||||
|
if "examples" in extra:
|
||||||
|
return extra["examples"]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class PydanticDateTimeData(RootModel):
|
class PydanticDateTimeData(RootModel):
|
||||||
"""Pydantic model for time series data with consistent value lengths.
|
"""Pydantic model for time series data with consistent value lengths.
|
||||||
@@ -795,9 +936,12 @@ class PydanticDateTimeDataFrame(PydanticBaseModel):
|
|||||||
|
|
||||||
data: Dict[str, Dict[str, Any]]
|
data: Dict[str, Dict[str, Any]]
|
||||||
dtypes: Dict[str, str] = Field(default_factory=dict)
|
dtypes: Dict[str, str] = Field(default_factory=dict)
|
||||||
tz: Optional[str] = Field(default=None, description="Timezone for datetime values")
|
tz: Optional[str] = Field(
|
||||||
|
default=None, json_schema_extra={"description": "Timezone for datetime values"}
|
||||||
|
)
|
||||||
datetime_columns: list[str] = Field(
|
datetime_columns: list[str] = Field(
|
||||||
default_factory=lambda: ["date_time"], description="Columns to be treated as datetime"
|
default_factory=lambda: ["date_time"],
|
||||||
|
json_schema_extra={"description": "Columns to be treated as datetime"},
|
||||||
)
|
)
|
||||||
|
|
||||||
@field_validator("tz")
|
@field_validator("tz")
|
||||||
|
|||||||
@@ -25,74 +25,81 @@ class BatteriesCommonSettings(DevicesBaseSettings):
|
|||||||
"""Battery devices base settings."""
|
"""Battery devices base settings."""
|
||||||
|
|
||||||
capacity_wh: int = Field(
|
capacity_wh: int = Field(
|
||||||
default=8000,
|
default=8000, gt=0, json_schema_extra={"description": "Capacity [Wh].", "examples": [8000]}
|
||||||
gt=0,
|
|
||||||
description="Capacity [Wh].",
|
|
||||||
examples=[8000],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
charging_efficiency: float = Field(
|
charging_efficiency: float = Field(
|
||||||
default=0.88,
|
default=0.88,
|
||||||
gt=0,
|
gt=0,
|
||||||
le=1,
|
le=1,
|
||||||
description="Charging efficiency [0.01 ... 1.00].",
|
json_schema_extra={
|
||||||
examples=[0.88],
|
"description": "Charging efficiency [0.01 ... 1.00].",
|
||||||
|
"examples": [0.88],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
discharging_efficiency: float = Field(
|
discharging_efficiency: float = Field(
|
||||||
default=0.88,
|
default=0.88,
|
||||||
gt=0,
|
gt=0,
|
||||||
le=1,
|
le=1,
|
||||||
description="Discharge efficiency [0.01 ... 1.00].",
|
json_schema_extra={
|
||||||
examples=[0.88],
|
"description": "Discharge efficiency [0.01 ... 1.00].",
|
||||||
|
"examples": [0.88],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
levelized_cost_of_storage_kwh: float = Field(
|
levelized_cost_of_storage_kwh: float = Field(
|
||||||
default=0.0,
|
default=0.0,
|
||||||
description="Levelized cost of storage (LCOS), the average lifetime cost of delivering one kWh [€/kWh].",
|
json_schema_extra={
|
||||||
examples=[0.12],
|
"description": "Levelized cost of storage (LCOS), the average lifetime cost of delivering one kWh [€/kWh].",
|
||||||
|
"examples": [0.12],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
max_charge_power_w: Optional[float] = Field(
|
max_charge_power_w: Optional[float] = Field(
|
||||||
default=5000,
|
default=5000,
|
||||||
gt=0,
|
gt=0,
|
||||||
description="Maximum charging power [W].",
|
json_schema_extra={"description": "Maximum charging power [W].", "examples": [5000]},
|
||||||
examples=[5000],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
min_charge_power_w: Optional[float] = Field(
|
min_charge_power_w: Optional[float] = Field(
|
||||||
default=50,
|
default=50,
|
||||||
gt=0,
|
gt=0,
|
||||||
description="Minimum charging power [W].",
|
json_schema_extra={"description": "Minimum charging power [W].", "examples": [50]},
|
||||||
examples=[50],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
charge_rates: Optional[NDArray[Shape["*"], float]] = Field(
|
charge_rates: Optional[NDArray[Shape["*"], float]] = Field(
|
||||||
default=BATTERY_DEFAULT_CHARGE_RATES,
|
default=BATTERY_DEFAULT_CHARGE_RATES,
|
||||||
description=(
|
json_schema_extra={
|
||||||
|
"description": (
|
||||||
"Charge rates as factor of maximum charging power [0.00 ... 1.00]. "
|
"Charge rates as factor of maximum charging power [0.00 ... 1.00]. "
|
||||||
"None triggers fallback to default charge-rates."
|
"None triggers fallback to default charge-rates."
|
||||||
),
|
),
|
||||||
examples=[[0.0, 0.25, 0.5, 0.75, 1.0], None],
|
"examples": [[0.0, 0.25, 0.5, 0.75, 1.0], None],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
min_soc_percentage: int = Field(
|
min_soc_percentage: int = Field(
|
||||||
default=0,
|
default=0,
|
||||||
ge=0,
|
ge=0,
|
||||||
le=100,
|
le=100,
|
||||||
description=(
|
json_schema_extra={
|
||||||
|
"description": (
|
||||||
"Minimum state of charge (SOC) as percentage of capacity [%]. "
|
"Minimum state of charge (SOC) as percentage of capacity [%]. "
|
||||||
"This is the target SoC for charging"
|
"This is the target SoC for charging"
|
||||||
),
|
),
|
||||||
examples=[10],
|
"examples": [10],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
max_soc_percentage: int = Field(
|
max_soc_percentage: int = Field(
|
||||||
default=100,
|
default=100,
|
||||||
ge=0,
|
ge=0,
|
||||||
le=100,
|
le=100,
|
||||||
description="Maximum state of charge (SOC) as percentage of capacity [%].",
|
json_schema_extra={
|
||||||
examples=[100],
|
"description": "Maximum state of charge (SOC) as percentage of capacity [%].",
|
||||||
|
"examples": [100],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@field_validator("charge_rates", mode="before")
|
@field_validator("charge_rates", mode="before")
|
||||||
@@ -178,14 +185,15 @@ class InverterCommonSettings(DevicesBaseSettings):
|
|||||||
max_power_w: Optional[float] = Field(
|
max_power_w: Optional[float] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
gt=0,
|
gt=0,
|
||||||
description="Maximum power [W].",
|
json_schema_extra={"description": "Maximum power [W].", "examples": [10000]},
|
||||||
examples=[10000],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
battery_id: Optional[str] = Field(
|
battery_id: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="ID of battery controlled by this inverter.",
|
json_schema_extra={
|
||||||
examples=[None, "battery1"],
|
"description": "ID of battery controlled by this inverter.",
|
||||||
|
"examples": [None, "battery1"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@computed_field # type: ignore[prop-decorator]
|
@computed_field # type: ignore[prop-decorator]
|
||||||
@@ -200,28 +208,27 @@ class HomeApplianceCommonSettings(DevicesBaseSettings):
|
|||||||
"""Home Appliance devices base settings."""
|
"""Home Appliance devices base settings."""
|
||||||
|
|
||||||
consumption_wh: int = Field(
|
consumption_wh: int = Field(
|
||||||
gt=0,
|
gt=0, json_schema_extra={"description": "Energy consumption [Wh].", "examples": [2000]}
|
||||||
description="Energy consumption [Wh].",
|
|
||||||
examples=[2000],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
duration_h: int = Field(
|
duration_h: int = Field(
|
||||||
gt=0,
|
gt=0,
|
||||||
le=24,
|
le=24,
|
||||||
description="Usage duration in hours [0 ... 24].",
|
json_schema_extra={"description": "Usage duration in hours [0 ... 24].", "examples": [1]},
|
||||||
examples=[1],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
time_windows: Optional[TimeWindowSequence] = Field(
|
time_windows: Optional[TimeWindowSequence] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Sequence of allowed time windows. Defaults to optimization general time window.",
|
json_schema_extra={
|
||||||
examples=[
|
"description": "Sequence of allowed time windows. Defaults to optimization general time window.",
|
||||||
|
"examples": [
|
||||||
{
|
{
|
||||||
"windows": [
|
"windows": [
|
||||||
{"start_time": "10:00", "duration": "2 hours"},
|
{"start_time": "10:00", "duration": "2 hours"},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@computed_field # type: ignore[prop-decorator]
|
@computed_field # type: ignore[prop-decorator]
|
||||||
@@ -237,50 +244,62 @@ class DevicesCommonSettings(SettingsBaseModel):
|
|||||||
|
|
||||||
batteries: Optional[list[BatteriesCommonSettings]] = Field(
|
batteries: Optional[list[BatteriesCommonSettings]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="List of battery devices",
|
json_schema_extra={
|
||||||
examples=[[{"device_id": "battery1", "capacity_wh": 8000}]],
|
"description": "List of battery devices",
|
||||||
|
"examples": [[{"device_id": "battery1", "capacity_wh": 8000}]],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
max_batteries: Optional[int] = Field(
|
max_batteries: Optional[int] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
ge=0,
|
ge=0,
|
||||||
description="Maximum number of batteries that can be set",
|
json_schema_extra={
|
||||||
examples=[1, 2],
|
"description": "Maximum number of batteries that can be set",
|
||||||
|
"examples": [1, 2],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
electric_vehicles: Optional[list[BatteriesCommonSettings]] = Field(
|
electric_vehicles: Optional[list[BatteriesCommonSettings]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="List of electric vehicle devices",
|
json_schema_extra={
|
||||||
examples=[[{"device_id": "battery1", "capacity_wh": 8000}]],
|
"description": "List of electric vehicle devices",
|
||||||
|
"examples": [[{"device_id": "battery1", "capacity_wh": 8000}]],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
max_electric_vehicles: Optional[int] = Field(
|
max_electric_vehicles: Optional[int] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
ge=0,
|
ge=0,
|
||||||
description="Maximum number of electric vehicles that can be set",
|
json_schema_extra={
|
||||||
examples=[1, 2],
|
"description": "Maximum number of electric vehicles that can be set",
|
||||||
|
"examples": [1, 2],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
inverters: Optional[list[InverterCommonSettings]] = Field(
|
inverters: Optional[list[InverterCommonSettings]] = Field(
|
||||||
default=None, description="List of inverters", examples=[[]]
|
default=None, json_schema_extra={"description": "List of inverters", "examples": [[]]}
|
||||||
)
|
)
|
||||||
|
|
||||||
max_inverters: Optional[int] = Field(
|
max_inverters: Optional[int] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
ge=0,
|
ge=0,
|
||||||
description="Maximum number of inverters that can be set",
|
json_schema_extra={
|
||||||
examples=[1, 2],
|
"description": "Maximum number of inverters that can be set",
|
||||||
|
"examples": [1, 2],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
home_appliances: Optional[list[HomeApplianceCommonSettings]] = Field(
|
home_appliances: Optional[list[HomeApplianceCommonSettings]] = Field(
|
||||||
default=None, description="List of home appliances", examples=[[]]
|
default=None, json_schema_extra={"description": "List of home appliances", "examples": [[]]}
|
||||||
)
|
)
|
||||||
|
|
||||||
max_home_appliances: Optional[int] = Field(
|
max_home_appliances: Optional[int] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
ge=0,
|
ge=0,
|
||||||
description="Maximum number of home_appliances that can be set",
|
json_schema_extra={
|
||||||
examples=[1, 2],
|
"description": "Maximum number of home_appliances that can be set",
|
||||||
|
"examples": [1, 2],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@computed_field # type: ignore[prop-decorator]
|
@computed_field # type: ignore[prop-decorator]
|
||||||
@@ -336,13 +355,17 @@ class ResourceRegistry(SingletonMixin, ConfigMixin, PydanticBaseModel):
|
|||||||
|
|
||||||
latest: dict[ResourceKey, ResourceStatus] = Field(
|
latest: dict[ResourceKey, ResourceStatus] = Field(
|
||||||
default_factory=dict,
|
default_factory=dict,
|
||||||
description="Latest resource status that was reported per resource key.",
|
json_schema_extra={
|
||||||
example=[],
|
"description": "Latest resource status that was reported per resource key.",
|
||||||
|
"example": [],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
history: dict[ResourceKey, list[tuple[DateTime, ResourceStatus]]] = Field(
|
history: dict[ResourceKey, list[tuple[DateTime, ResourceStatus]]] = Field(
|
||||||
default_factory=dict,
|
default_factory=dict,
|
||||||
description="History of resource stati that were reported per resource key.",
|
json_schema_extra={
|
||||||
example=[],
|
"description": "History of resource stati that were reported per resource key.",
|
||||||
|
"example": [],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
|
|||||||
@@ -12,8 +12,10 @@ class DevicesBaseSettings(SettingsBaseModel):
|
|||||||
|
|
||||||
device_id: str = Field(
|
device_id: str = Field(
|
||||||
default="<unknown>",
|
default="<unknown>",
|
||||||
description="ID of device",
|
json_schema_extra={
|
||||||
examples=["battery1", "ev1", "inverter1", "dishwasher"],
|
"description": "ID of device",
|
||||||
|
"examples": ["battery1", "ev1", "inverter1", "dishwasher"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -24,26 +24,34 @@ class MeasurementCommonSettings(SettingsBaseModel):
|
|||||||
|
|
||||||
load_emr_keys: Optional[list[str]] = Field(
|
load_emr_keys: Optional[list[str]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="The keys of the measurements that are energy meter readings of a load [kWh].",
|
json_schema_extra={
|
||||||
examples=[["load0_emr"]],
|
"description": "The keys of the measurements that are energy meter readings of a load [kWh].",
|
||||||
|
"examples": [["load0_emr"]],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
grid_export_emr_keys: Optional[list[str]] = Field(
|
grid_export_emr_keys: Optional[list[str]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="The keys of the measurements that are energy meter readings of energy export to grid [kWh].",
|
json_schema_extra={
|
||||||
examples=[["grid_export_emr"]],
|
"description": "The keys of the measurements that are energy meter readings of energy export to grid [kWh].",
|
||||||
|
"examples": [["grid_export_emr"]],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
grid_import_emr_keys: Optional[list[str]] = Field(
|
grid_import_emr_keys: Optional[list[str]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="The keys of the measurements that are energy meter readings of energy import from grid [kWh].",
|
json_schema_extra={
|
||||||
examples=[["grid_import_emr"]],
|
"description": "The keys of the measurements that are energy meter readings of energy import from grid [kWh].",
|
||||||
|
"examples": [["grid_import_emr"]],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
pv_production_emr_keys: Optional[list[str]] = Field(
|
pv_production_emr_keys: Optional[list[str]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="The keys of the measurements that are PV production energy meter readings [kWh].",
|
json_schema_extra={
|
||||||
examples=[["pv1_emr"]],
|
"description": "The keys of the measurements that are PV production energy meter readings [kWh].",
|
||||||
|
"examples": [["pv1_emr"]],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
## Computed fields
|
## Computed fields
|
||||||
@@ -78,7 +86,7 @@ class Measurement(SingletonMixin, DataImportMixin, DataSequence):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
records: list[MeasurementDataRecord] = Field(
|
records: list[MeasurementDataRecord] = Field(
|
||||||
default_factory=list, description="list of measurement data records"
|
default_factory=list, json_schema_extra={"description": "list of measurement data records"}
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
|
|||||||
@@ -34,50 +34,74 @@ class GeneticSimulation(PydanticBaseModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
start_hour: int = Field(
|
start_hour: int = Field(
|
||||||
default=0, ge=0, le=23, description="Starting hour on day for optimizations."
|
default=0,
|
||||||
|
ge=0,
|
||||||
|
le=23,
|
||||||
|
json_schema_extra={"description": "Starting hour on day for optimizations."},
|
||||||
)
|
)
|
||||||
|
|
||||||
optimization_hours: Optional[int] = Field(
|
optimization_hours: Optional[int] = Field(
|
||||||
default=24, ge=0, description="Number of hours into the future for optimizations."
|
default=24,
|
||||||
|
ge=0,
|
||||||
|
json_schema_extra={"description": "Number of hours into the future for optimizations."},
|
||||||
)
|
)
|
||||||
|
|
||||||
prediction_hours: Optional[int] = Field(
|
prediction_hours: Optional[int] = Field(
|
||||||
default=48, ge=0, description="Number of hours into the future for predictions"
|
default=48,
|
||||||
|
ge=0,
|
||||||
|
json_schema_extra={"description": "Number of hours into the future for predictions"},
|
||||||
)
|
)
|
||||||
|
|
||||||
load_energy_array: Optional[NDArray[Shape["*"], float]] = Field(
|
load_energy_array: Optional[NDArray[Shape["*"], float]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="An array of floats representing the total load (consumption) in watts for different time intervals.",
|
json_schema_extra={
|
||||||
|
"description": "An array of floats representing the total load (consumption) in watts for different time intervals."
|
||||||
|
},
|
||||||
)
|
)
|
||||||
pv_prediction_wh: Optional[NDArray[Shape["*"], float]] = Field(
|
pv_prediction_wh: Optional[NDArray[Shape["*"], float]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="An array of floats representing the forecasted photovoltaic output in watts for different time intervals.",
|
json_schema_extra={
|
||||||
|
"description": "An array of floats representing the forecasted photovoltaic output in watts for different time intervals."
|
||||||
|
},
|
||||||
)
|
)
|
||||||
elect_price_hourly: Optional[NDArray[Shape["*"], float]] = Field(
|
elect_price_hourly: Optional[NDArray[Shape["*"], float]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="An array of floats representing the electricity price in euros per watt-hour for different time intervals.",
|
json_schema_extra={
|
||||||
|
"description": "An array of floats representing the electricity price in euros per watt-hour for different time intervals."
|
||||||
|
},
|
||||||
)
|
)
|
||||||
elect_revenue_per_hour_arr: Optional[NDArray[Shape["*"], float]] = Field(
|
elect_revenue_per_hour_arr: Optional[NDArray[Shape["*"], float]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="An array of floats representing the feed-in compensation in euros per watt-hour.",
|
json_schema_extra={
|
||||||
|
"description": "An array of floats representing the feed-in compensation in euros per watt-hour."
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
battery: Optional[Battery] = Field(default=None, description="TBD.")
|
battery: Optional[Battery] = Field(default=None, json_schema_extra={"description": "TBD."})
|
||||||
ev: Optional[Battery] = Field(default=None, description="TBD.")
|
ev: Optional[Battery] = Field(default=None, json_schema_extra={"description": "TBD."})
|
||||||
home_appliance: Optional[HomeAppliance] = Field(default=None, description="TBD.")
|
home_appliance: Optional[HomeAppliance] = Field(
|
||||||
inverter: Optional[Inverter] = Field(default=None, description="TBD.")
|
default=None, json_schema_extra={"description": "TBD."}
|
||||||
|
)
|
||||||
|
inverter: Optional[Inverter] = Field(default=None, json_schema_extra={"description": "TBD."})
|
||||||
|
|
||||||
ac_charge_hours: Optional[NDArray[Shape["*"], float]] = Field(default=None, description="TBD")
|
ac_charge_hours: Optional[NDArray[Shape["*"], float]] = Field(
|
||||||
dc_charge_hours: Optional[NDArray[Shape["*"], float]] = Field(default=None, description="TBD")
|
default=None, json_schema_extra={"description": "TBD"}
|
||||||
|
)
|
||||||
|
dc_charge_hours: Optional[NDArray[Shape["*"], float]] = Field(
|
||||||
|
default=None, json_schema_extra={"description": "TBD"}
|
||||||
|
)
|
||||||
bat_discharge_hours: Optional[NDArray[Shape["*"], float]] = Field(
|
bat_discharge_hours: Optional[NDArray[Shape["*"], float]] = Field(
|
||||||
default=None, description="TBD"
|
default=None, json_schema_extra={"description": "TBD"}
|
||||||
|
)
|
||||||
|
ev_charge_hours: Optional[NDArray[Shape["*"], float]] = Field(
|
||||||
|
default=None, json_schema_extra={"description": "TBD"}
|
||||||
)
|
)
|
||||||
ev_charge_hours: Optional[NDArray[Shape["*"], float]] = Field(default=None, description="TBD")
|
|
||||||
ev_discharge_hours: Optional[NDArray[Shape["*"], float]] = Field(
|
ev_discharge_hours: Optional[NDArray[Shape["*"], float]] = Field(
|
||||||
default=None, description="TBD"
|
default=None, json_schema_extra={"description": "TBD"}
|
||||||
)
|
)
|
||||||
home_appliance_start_hour: Optional[int] = Field(
|
home_appliance_start_hour: Optional[int] = Field(
|
||||||
default=None, description="Home appliance start hour - None denotes no start."
|
default=None,
|
||||||
|
json_schema_extra={"description": "Home appliance start hour - None denotes no start."},
|
||||||
)
|
)
|
||||||
|
|
||||||
def prepare(
|
def prepare(
|
||||||
|
|||||||
@@ -9,27 +9,27 @@ from akkudoktoreos.utils.datetimeutil import TimeWindowSequence
|
|||||||
|
|
||||||
|
|
||||||
class DeviceParameters(GeneticParametersBaseModel):
|
class DeviceParameters(GeneticParametersBaseModel):
|
||||||
device_id: str = Field(description="ID of device", examples="device1")
|
device_id: str = Field(json_schema_extra={"description": "ID of device", "examples": "device1"})
|
||||||
hours: Optional[int] = Field(
|
hours: Optional[int] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
gt=0,
|
gt=0,
|
||||||
description="Number of prediction hours. Defaults to global config prediction hours.",
|
json_schema_extra={
|
||||||
examples=[None],
|
"description": "Number of prediction hours. Defaults to global config prediction hours.",
|
||||||
|
"examples": [None],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def max_charging_power_field(description: Optional[str] = None) -> float:
|
def max_charging_power_field(description: Optional[str] = None) -> float:
|
||||||
if description is None:
|
if description is None:
|
||||||
description = "Maximum charging power in watts."
|
description = "Maximum charging power in watts."
|
||||||
return Field(
|
return Field(default=5000, gt=0, json_schema_extra={"description": description})
|
||||||
default=5000,
|
|
||||||
gt=0,
|
|
||||||
description=description,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def initial_soc_percentage_field(description: str) -> int:
|
def initial_soc_percentage_field(description: str) -> int:
|
||||||
return Field(default=0, ge=0, le=100, description=description, examples=[42])
|
return Field(
|
||||||
|
default=0, ge=0, le=100, json_schema_extra={"description": description, "examples": [42]}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def discharging_efficiency_field(default_value: float) -> float:
|
def discharging_efficiency_field(default_value: float) -> float:
|
||||||
@@ -37,24 +37,32 @@ def discharging_efficiency_field(default_value: float) -> float:
|
|||||||
default=default_value,
|
default=default_value,
|
||||||
gt=0,
|
gt=0,
|
||||||
le=1,
|
le=1,
|
||||||
description="A float representing the discharge efficiency of the battery.",
|
json_schema_extra={
|
||||||
|
"description": "A float representing the discharge efficiency of the battery."
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BaseBatteryParameters(DeviceParameters):
|
class BaseBatteryParameters(DeviceParameters):
|
||||||
"""Battery Device Simulation Configuration."""
|
"""Battery Device Simulation Configuration."""
|
||||||
|
|
||||||
device_id: str = Field(description="ID of battery", examples=["battery1"])
|
device_id: str = Field(
|
||||||
|
json_schema_extra={"description": "ID of battery", "examples": ["battery1"]}
|
||||||
|
)
|
||||||
capacity_wh: int = Field(
|
capacity_wh: int = Field(
|
||||||
gt=0,
|
gt=0,
|
||||||
description="An integer representing the capacity of the battery in watt-hours.",
|
json_schema_extra={
|
||||||
examples=[8000],
|
"description": "An integer representing the capacity of the battery in watt-hours.",
|
||||||
|
"examples": [8000],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
charging_efficiency: float = Field(
|
charging_efficiency: float = Field(
|
||||||
default=0.88,
|
default=0.88,
|
||||||
gt=0,
|
gt=0,
|
||||||
le=1,
|
le=1,
|
||||||
description="A float representing the charging efficiency of the battery.",
|
json_schema_extra={
|
||||||
|
"description": "A float representing the charging efficiency of the battery."
|
||||||
|
},
|
||||||
)
|
)
|
||||||
discharging_efficiency: float = discharging_efficiency_field(0.88)
|
discharging_efficiency: float = discharging_efficiency_field(0.88)
|
||||||
max_charge_power_w: Optional[float] = max_charging_power_field()
|
max_charge_power_w: Optional[float] = max_charging_power_field()
|
||||||
@@ -65,19 +73,25 @@ class BaseBatteryParameters(DeviceParameters):
|
|||||||
default=0,
|
default=0,
|
||||||
ge=0,
|
ge=0,
|
||||||
le=100,
|
le=100,
|
||||||
description="An integer representing the minimum state of charge (SOC) of the battery in percentage.",
|
json_schema_extra={
|
||||||
examples=[10],
|
"description": "An integer representing the minimum state of charge (SOC) of the battery in percentage.",
|
||||||
|
"examples": [10],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
max_soc_percentage: int = Field(
|
max_soc_percentage: int = Field(
|
||||||
default=100,
|
default=100,
|
||||||
ge=0,
|
ge=0,
|
||||||
le=100,
|
le=100,
|
||||||
description="An integer representing the maximum state of charge (SOC) of the battery in percentage.",
|
json_schema_extra={
|
||||||
|
"description": "An integer representing the maximum state of charge (SOC) of the battery in percentage."
|
||||||
|
},
|
||||||
)
|
)
|
||||||
charge_rates: Optional[list[float]] = Field(
|
charge_rates: Optional[list[float]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Charge rates as factor of maximum charging power [0.00 ... 1.00]. None denotes all charge rates are available.",
|
json_schema_extra={
|
||||||
examples=[[0.0, 0.25, 0.5, 0.75, 1.0], None],
|
"description": "Charge rates as factor of maximum charging power [0.00 ... 1.00]. None denotes all charge rates are available.",
|
||||||
|
"examples": [[0.0, 0.25, 0.5, 0.75, 1.0], None],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -90,7 +104,9 @@ class SolarPanelBatteryParameters(BaseBatteryParameters):
|
|||||||
class ElectricVehicleParameters(BaseBatteryParameters):
|
class ElectricVehicleParameters(BaseBatteryParameters):
|
||||||
"""Battery Electric Vehicle Device Simulation Configuration."""
|
"""Battery Electric Vehicle Device Simulation Configuration."""
|
||||||
|
|
||||||
device_id: str = Field(description="ID of electric vehicle", examples=["ev1"])
|
device_id: str = Field(
|
||||||
|
json_schema_extra={"description": "ID of electric vehicle", "examples": ["ev1"]}
|
||||||
|
)
|
||||||
discharging_efficiency: float = discharging_efficiency_field(1.0)
|
discharging_efficiency: float = discharging_efficiency_field(1.0)
|
||||||
initial_soc_percentage: int = initial_soc_percentage_field(
|
initial_soc_percentage: int = initial_soc_percentage_field(
|
||||||
"An integer representing the current state of charge (SOC) of the battery in percentage."
|
"An integer representing the current state of charge (SOC) of the battery in percentage."
|
||||||
@@ -100,33 +116,44 @@ class ElectricVehicleParameters(BaseBatteryParameters):
|
|||||||
class HomeApplianceParameters(DeviceParameters):
|
class HomeApplianceParameters(DeviceParameters):
|
||||||
"""Home Appliance Device Simulation Configuration."""
|
"""Home Appliance Device Simulation Configuration."""
|
||||||
|
|
||||||
device_id: str = Field(description="ID of home appliance", examples=["dishwasher"])
|
device_id: str = Field(
|
||||||
|
json_schema_extra={"description": "ID of home appliance", "examples": ["dishwasher"]}
|
||||||
|
)
|
||||||
consumption_wh: int = Field(
|
consumption_wh: int = Field(
|
||||||
gt=0,
|
gt=0,
|
||||||
description="An integer representing the energy consumption of a household device in watt-hours.",
|
json_schema_extra={
|
||||||
examples=[2000],
|
"description": "An integer representing the energy consumption of a household device in watt-hours.",
|
||||||
|
"examples": [2000],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
duration_h: int = Field(
|
duration_h: int = Field(
|
||||||
gt=0,
|
gt=0,
|
||||||
description="An integer representing the usage duration of a household device in hours.",
|
json_schema_extra={
|
||||||
examples=[3],
|
"description": "An integer representing the usage duration of a household device in hours.",
|
||||||
|
"examples": [3],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
time_windows: Optional[TimeWindowSequence] = Field(
|
time_windows: Optional[TimeWindowSequence] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="List of allowed time windows. Defaults to optimization general time window.",
|
json_schema_extra={
|
||||||
examples=[
|
"description": "List of allowed time windows. Defaults to optimization general time window.",
|
||||||
|
"examples": [
|
||||||
[
|
[
|
||||||
{"start_time": "10:00", "duration": "2 hours"},
|
{"start_time": "10:00", "duration": "2 hours"},
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class InverterParameters(DeviceParameters):
|
class InverterParameters(DeviceParameters):
|
||||||
"""Inverter Device Simulation Configuration."""
|
"""Inverter Device Simulation Configuration."""
|
||||||
|
|
||||||
device_id: str = Field(description="ID of inverter", examples=["inverter1"])
|
device_id: str = Field(
|
||||||
max_power_wh: float = Field(gt=0, examples=[10000])
|
json_schema_extra={"description": "ID of inverter", "examples": ["inverter1"]}
|
||||||
battery_id: Optional[str] = Field(
|
)
|
||||||
default=None, description="ID of battery", examples=[None, "battery1"]
|
max_power_wh: float = Field(gt=0, json_schema_extra={"examples": [10000]})
|
||||||
|
battery_id: Optional[str] = Field(
|
||||||
|
default=None,
|
||||||
|
json_schema_extra={"description": "ID of battery", "examples": [None, "battery1"]},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -37,19 +37,29 @@ class GeneticEnergyManagementParameters(GeneticParametersBaseModel):
|
|||||||
"""Encapsulates energy-related forecasts and costs used in GENETIC optimization."""
|
"""Encapsulates energy-related forecasts and costs used in GENETIC optimization."""
|
||||||
|
|
||||||
pv_prognose_wh: list[float] = Field(
|
pv_prognose_wh: list[float] = Field(
|
||||||
description="An array of floats representing the forecasted photovoltaic output in watts for different time intervals."
|
json_schema_extra={
|
||||||
|
"description": "An array of floats representing the forecasted photovoltaic output in watts for different time intervals."
|
||||||
|
}
|
||||||
)
|
)
|
||||||
strompreis_euro_pro_wh: list[float] = Field(
|
strompreis_euro_pro_wh: list[float] = Field(
|
||||||
description="An array of floats representing the electricity price in euros per watt-hour for different time intervals."
|
json_schema_extra={
|
||||||
|
"description": "An array of floats representing the electricity price in euros per watt-hour for different time intervals."
|
||||||
|
}
|
||||||
)
|
)
|
||||||
einspeiseverguetung_euro_pro_wh: Union[list[float], float] = Field(
|
einspeiseverguetung_euro_pro_wh: Union[list[float], float] = Field(
|
||||||
description="A float or array of floats representing the feed-in compensation in euros per watt-hour."
|
json_schema_extra={
|
||||||
|
"description": "A float or array of floats representing the feed-in compensation in euros per watt-hour."
|
||||||
|
}
|
||||||
)
|
)
|
||||||
preis_euro_pro_wh_akku: float = Field(
|
preis_euro_pro_wh_akku: float = Field(
|
||||||
description="A float representing the cost of battery energy per watt-hour."
|
json_schema_extra={
|
||||||
|
"description": "A float representing the cost of battery energy per watt-hour."
|
||||||
|
}
|
||||||
)
|
)
|
||||||
gesamtlast: list[float] = Field(
|
gesamtlast: list[float] = Field(
|
||||||
description="An array of floats representing the total load (consumption) in watts for different time intervals."
|
json_schema_extra={
|
||||||
|
"description": "An array of floats representing the total load (consumption) in watts for different time intervals."
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
@@ -93,10 +103,15 @@ class GeneticOptimizationParameters(
|
|||||||
dishwasher: Optional[HomeApplianceParameters] = None
|
dishwasher: Optional[HomeApplianceParameters] = None
|
||||||
temperature_forecast: Optional[list[Optional[float]]] = Field(
|
temperature_forecast: Optional[list[Optional[float]]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="An array of floats representing the temperature forecast in degrees Celsius for different time intervals.",
|
json_schema_extra={
|
||||||
|
"description": "An array of floats representing the temperature forecast in degrees Celsius for different time intervals."
|
||||||
|
},
|
||||||
)
|
)
|
||||||
start_solution: Optional[list[float]] = Field(
|
start_solution: Optional[list[float]] = Field(
|
||||||
default=None, description="Can be `null` or contain a previous solution (if available)."
|
default=None,
|
||||||
|
json_schema_extra={
|
||||||
|
"description": "Can be `null` or contain a previous solution (if available)."
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
|
|||||||
@@ -28,29 +28,52 @@ from akkudoktoreos.utils.utils import NumpyEncoder
|
|||||||
|
|
||||||
|
|
||||||
class DeviceOptimizeResult(GeneticParametersBaseModel):
|
class DeviceOptimizeResult(GeneticParametersBaseModel):
|
||||||
device_id: str = Field(description="ID of device", examples=["device1"])
|
device_id: str = Field(
|
||||||
hours: int = Field(gt=0, description="Number of hours in the simulation.", examples=[24])
|
json_schema_extra={"description": "ID of device", "examples": ["device1"]}
|
||||||
|
)
|
||||||
|
hours: int = Field(
|
||||||
|
gt=0,
|
||||||
|
json_schema_extra={"description": "Number of hours in the simulation.", "examples": [24]},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ElectricVehicleResult(DeviceOptimizeResult):
|
class ElectricVehicleResult(DeviceOptimizeResult):
|
||||||
"""Result class containing information related to the electric vehicle's charging and discharging behavior."""
|
"""Result class containing information related to the electric vehicle's charging and discharging behavior."""
|
||||||
|
|
||||||
device_id: str = Field(description="ID of electric vehicle", examples=["ev1"])
|
device_id: str = Field(
|
||||||
|
json_schema_extra={"description": "ID of electric vehicle", "examples": ["ev1"]}
|
||||||
|
)
|
||||||
charge_array: list[float] = Field(
|
charge_array: list[float] = Field(
|
||||||
description="Hourly charging status (0 for no charging, 1 for charging)."
|
json_schema_extra={
|
||||||
|
"description": "Hourly charging status (0 for no charging, 1 for charging)."
|
||||||
|
}
|
||||||
)
|
)
|
||||||
discharge_array: list[int] = Field(
|
discharge_array: list[int] = Field(
|
||||||
description="Hourly discharging status (0 for no discharging, 1 for discharging)."
|
json_schema_extra={
|
||||||
|
"description": "Hourly discharging status (0 for no discharging, 1 for discharging)."
|
||||||
|
}
|
||||||
|
)
|
||||||
|
discharging_efficiency: float = Field(
|
||||||
|
json_schema_extra={"description": "The discharge efficiency as a float.."}
|
||||||
|
)
|
||||||
|
capacity_wh: int = Field(
|
||||||
|
json_schema_extra={"description": "Capacity of the EV’s battery in watt-hours."}
|
||||||
|
)
|
||||||
|
charging_efficiency: float = Field(
|
||||||
|
json_schema_extra={"description": "Charging efficiency as a float.."}
|
||||||
|
)
|
||||||
|
max_charge_power_w: int = Field(
|
||||||
|
json_schema_extra={"description": "Maximum charging power in watts."}
|
||||||
)
|
)
|
||||||
discharging_efficiency: float = Field(description="The discharge efficiency as a float..")
|
|
||||||
capacity_wh: int = Field(description="Capacity of the EV’s battery in watt-hours.")
|
|
||||||
charging_efficiency: float = Field(description="Charging efficiency as a float..")
|
|
||||||
max_charge_power_w: int = Field(description="Maximum charging power in watts.")
|
|
||||||
soc_wh: float = Field(
|
soc_wh: float = Field(
|
||||||
description="State of charge of the battery in watt-hours at the start of the simulation."
|
json_schema_extra={
|
||||||
|
"description": "State of charge of the battery in watt-hours at the start of the simulation."
|
||||||
|
}
|
||||||
)
|
)
|
||||||
initial_soc_percentage: int = Field(
|
initial_soc_percentage: int = Field(
|
||||||
description="State of charge at the start of the simulation in percentage."
|
json_schema_extra={
|
||||||
|
"description": "State of charge at the start of the simulation in percentage."
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@field_validator("discharge_array", "charge_array", mode="before")
|
@field_validator("discharge_array", "charge_array", mode="before")
|
||||||
@@ -61,37 +84,49 @@ class ElectricVehicleResult(DeviceOptimizeResult):
|
|||||||
class GeneticSimulationResult(GeneticParametersBaseModel):
|
class GeneticSimulationResult(GeneticParametersBaseModel):
|
||||||
"""This object contains the results of the simulation and provides insights into various parameters over the entire forecast period."""
|
"""This object contains the results of the simulation and provides insights into various parameters over the entire forecast period."""
|
||||||
|
|
||||||
Last_Wh_pro_Stunde: list[float] = Field(description="TBD")
|
Last_Wh_pro_Stunde: list[float] = Field(json_schema_extra={"description": "TBD"})
|
||||||
EAuto_SoC_pro_Stunde: list[float] = Field(
|
EAuto_SoC_pro_Stunde: list[float] = Field(
|
||||||
description="The state of charge of the EV for each hour."
|
json_schema_extra={"description": "The state of charge of the EV for each hour."}
|
||||||
)
|
)
|
||||||
Einnahmen_Euro_pro_Stunde: list[float] = Field(
|
Einnahmen_Euro_pro_Stunde: list[float] = Field(
|
||||||
description="The revenue from grid feed-in or other sources in euros per hour."
|
json_schema_extra={
|
||||||
|
"description": "The revenue from grid feed-in or other sources in euros per hour."
|
||||||
|
}
|
||||||
)
|
)
|
||||||
Gesamt_Verluste: float = Field(
|
Gesamt_Verluste: float = Field(
|
||||||
description="The total losses in watt-hours over the entire period."
|
json_schema_extra={"description": "The total losses in watt-hours over the entire period."}
|
||||||
)
|
)
|
||||||
Gesamtbilanz_Euro: float = Field(
|
Gesamtbilanz_Euro: float = Field(
|
||||||
description="The total balance of revenues minus costs in euros."
|
json_schema_extra={"description": "The total balance of revenues minus costs in euros."}
|
||||||
)
|
)
|
||||||
Gesamteinnahmen_Euro: float = Field(description="The total revenues in euros.")
|
Gesamteinnahmen_Euro: float = Field(
|
||||||
Gesamtkosten_Euro: float = Field(description="The total costs in euros.")
|
json_schema_extra={"description": "The total revenues in euros."}
|
||||||
|
)
|
||||||
|
Gesamtkosten_Euro: float = Field(json_schema_extra={"description": "The total costs in euros."})
|
||||||
Home_appliance_wh_per_hour: list[Optional[float]] = Field(
|
Home_appliance_wh_per_hour: list[Optional[float]] = Field(
|
||||||
description="The energy consumption of a household appliance in watt-hours per hour."
|
json_schema_extra={
|
||||||
|
"description": "The energy consumption of a household appliance in watt-hours per hour."
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Kosten_Euro_pro_Stunde: list[float] = Field(
|
||||||
|
json_schema_extra={"description": "The costs in euros per hour."}
|
||||||
)
|
)
|
||||||
Kosten_Euro_pro_Stunde: list[float] = Field(description="The costs in euros per hour.")
|
|
||||||
Netzbezug_Wh_pro_Stunde: list[float] = Field(
|
Netzbezug_Wh_pro_Stunde: list[float] = Field(
|
||||||
description="The grid energy drawn in watt-hours per hour."
|
json_schema_extra={"description": "The grid energy drawn in watt-hours per hour."}
|
||||||
)
|
)
|
||||||
Netzeinspeisung_Wh_pro_Stunde: list[float] = Field(
|
Netzeinspeisung_Wh_pro_Stunde: list[float] = Field(
|
||||||
description="The energy fed into the grid in watt-hours per hour."
|
json_schema_extra={"description": "The energy fed into the grid in watt-hours per hour."}
|
||||||
|
)
|
||||||
|
Verluste_Pro_Stunde: list[float] = Field(
|
||||||
|
json_schema_extra={"description": "The losses in watt-hours per hour."}
|
||||||
)
|
)
|
||||||
Verluste_Pro_Stunde: list[float] = Field(description="The losses in watt-hours per hour.")
|
|
||||||
akku_soc_pro_stunde: list[float] = Field(
|
akku_soc_pro_stunde: list[float] = Field(
|
||||||
description="The state of charge of the battery (not the EV) in percentage per hour."
|
json_schema_extra={
|
||||||
|
"description": "The state of charge of the battery (not the EV) in percentage per hour."
|
||||||
|
}
|
||||||
)
|
)
|
||||||
Electricity_price: list[float] = Field(
|
Electricity_price: list[float] = Field(
|
||||||
description="Used Electricity Price, including predictions"
|
json_schema_extra={"description": "Used Electricity Price, including predictions"}
|
||||||
)
|
)
|
||||||
|
|
||||||
@field_validator(
|
@field_validator(
|
||||||
@@ -115,24 +150,34 @@ class GeneticSolution(ConfigMixin, GeneticParametersBaseModel):
|
|||||||
"""**Note**: The first value of "Last_Wh_per_hour", "Netzeinspeisung_Wh_per_hour", and "Netzbezug_Wh_per_hour", will be set to null in the JSON output and represented as NaN or None in the corresponding classes' data returns. This approach is adopted to ensure that the current hour's processing remains unchanged."""
|
"""**Note**: The first value of "Last_Wh_per_hour", "Netzeinspeisung_Wh_per_hour", and "Netzbezug_Wh_per_hour", will be set to null in the JSON output and represented as NaN or None in the corresponding classes' data returns. This approach is adopted to ensure that the current hour's processing remains unchanged."""
|
||||||
|
|
||||||
ac_charge: list[float] = Field(
|
ac_charge: list[float] = Field(
|
||||||
description="Array with AC charging values as relative power (0.0-1.0), other values set to 0."
|
json_schema_extra={
|
||||||
|
"description": "Array with AC charging values as relative power (0.0-1.0), other values set to 0."
|
||||||
|
}
|
||||||
)
|
)
|
||||||
dc_charge: list[float] = Field(
|
dc_charge: list[float] = Field(
|
||||||
description="Array with DC charging values as relative power (0-1), other values set to 0."
|
json_schema_extra={
|
||||||
|
"description": "Array with DC charging values as relative power (0-1), other values set to 0."
|
||||||
|
}
|
||||||
)
|
)
|
||||||
discharge_allowed: list[int] = Field(
|
discharge_allowed: list[int] = Field(
|
||||||
description="Array with discharge values (1 for discharge, 0 otherwise)."
|
json_schema_extra={
|
||||||
|
"description": "Array with discharge values (1 for discharge, 0 otherwise)."
|
||||||
|
}
|
||||||
)
|
)
|
||||||
eautocharge_hours_float: Optional[list[float]] = Field(description="TBD")
|
eautocharge_hours_float: Optional[list[float]] = Field(json_schema_extra={"description": "TBD"})
|
||||||
result: GeneticSimulationResult
|
result: GeneticSimulationResult
|
||||||
eauto_obj: Optional[ElectricVehicleResult]
|
eauto_obj: Optional[ElectricVehicleResult]
|
||||||
start_solution: Optional[list[float]] = Field(
|
start_solution: Optional[list[float]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="An array of binary values (0 or 1) representing a possible starting solution for the simulation.",
|
json_schema_extra={
|
||||||
|
"description": "An array of binary values (0 or 1) representing a possible starting solution for the simulation."
|
||||||
|
},
|
||||||
)
|
)
|
||||||
washingstart: Optional[int] = Field(
|
washingstart: Optional[int] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Can be `null` or contain an object representing the start of washing (if applicable).",
|
json_schema_extra={
|
||||||
|
"description": "Can be `null` or contain an object representing the start of washing (if applicable)."
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@field_validator(
|
@field_validator(
|
||||||
|
|||||||
@@ -16,30 +16,38 @@ class GeneticCommonSettings(SettingsBaseModel):
|
|||||||
individuals: Optional[int] = Field(
|
individuals: Optional[int] = Field(
|
||||||
default=300,
|
default=300,
|
||||||
ge=10,
|
ge=10,
|
||||||
description="Number of individuals (solutions) to generate for the (initial) generation [>= 10]. Defaults to 300.",
|
json_schema_extra={
|
||||||
examples=[300],
|
"description": "Number of individuals (solutions) to generate for the (initial) generation [>= 10]. Defaults to 300.",
|
||||||
|
"examples": [300],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
generations: Optional[int] = Field(
|
generations: Optional[int] = Field(
|
||||||
default=400,
|
default=400,
|
||||||
ge=10,
|
ge=10,
|
||||||
description="Number of generations to evaluate the optimal solution [>= 10]. Defaults to 400.",
|
json_schema_extra={
|
||||||
examples=[400],
|
"description": "Number of generations to evaluate the optimal solution [>= 10]. Defaults to 400.",
|
||||||
|
"examples": [400],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
seed: Optional[int] = Field(
|
seed: Optional[int] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
ge=0,
|
ge=0,
|
||||||
description="Fixed seed for genetic algorithm. Defaults to 'None' which means random seed.",
|
json_schema_extra={
|
||||||
examples=[None],
|
"description": "Fixed seed for genetic algorithm. Defaults to 'None' which means random seed.",
|
||||||
|
"examples": [None],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
penalties: Optional[dict[str, Union[float, int, str]]] = Field(
|
penalties: Optional[dict[str, Union[float, int, str]]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="A dictionary of penalty function parameters consisting of a penalty function parameter name and the associated value.",
|
json_schema_extra={
|
||||||
examples=[
|
"description": "A dictionary of penalty function parameters consisting of a penalty function parameter name and the associated value.",
|
||||||
|
"examples": [
|
||||||
{"ev_soc_miss": 10},
|
{"ev_soc_miss": 10},
|
||||||
],
|
],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -49,28 +57,33 @@ class OptimizationCommonSettings(SettingsBaseModel):
|
|||||||
horizon_hours: Optional[int] = Field(
|
horizon_hours: Optional[int] = Field(
|
||||||
default=24,
|
default=24,
|
||||||
ge=0,
|
ge=0,
|
||||||
description="The general time window within which the energy optimization goal shall be achieved [h]. Defaults to 24 hours.",
|
json_schema_extra={
|
||||||
examples=[24],
|
"description": "The general time window within which the energy optimization goal shall be achieved [h]. Defaults to 24 hours.",
|
||||||
|
"examples": [24],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
interval: Optional[int] = Field(
|
interval: Optional[int] = Field(
|
||||||
default=3600,
|
default=3600,
|
||||||
ge=15 * 60,
|
ge=15 * 60,
|
||||||
le=60 * 60,
|
le=60 * 60,
|
||||||
description="The optimization interval [sec].",
|
json_schema_extra={
|
||||||
examples=[60 * 60, 15 * 60],
|
"description": "The optimization interval [sec].",
|
||||||
|
"examples": [60 * 60, 15 * 60],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
algorithm: Optional[str] = Field(
|
algorithm: Optional[str] = Field(
|
||||||
default="GENETIC",
|
default="GENETIC",
|
||||||
description="The optimization algorithm.",
|
json_schema_extra={"description": "The optimization algorithm.", "examples": ["GENETIC"]},
|
||||||
examples=["GENETIC"],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
genetic: Optional[GeneticCommonSettings] = Field(
|
genetic: Optional[GeneticCommonSettings] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Genetic optimization algorithm configuration.",
|
json_schema_extra={
|
||||||
examples=[{"individuals": 400, "seed": None, "penalties": {"ev_soc_miss": 10}}],
|
"description": "Genetic optimization algorithm configuration.",
|
||||||
|
"examples": [{"individuals": 400, "seed": None, "penalties": {"ev_soc_miss": 10}}],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
@@ -85,35 +98,46 @@ class OptimizationCommonSettings(SettingsBaseModel):
|
|||||||
class OptimizationSolution(PydanticBaseModel):
|
class OptimizationSolution(PydanticBaseModel):
|
||||||
"""General Optimization Solution."""
|
"""General Optimization Solution."""
|
||||||
|
|
||||||
id: str = Field(..., description="Unique ID for the optimization solution.")
|
id: str = Field(
|
||||||
|
..., json_schema_extra={"description": "Unique ID for the optimization solution."}
|
||||||
|
)
|
||||||
|
|
||||||
generated_at: DateTime = Field(..., description="Timestamp when the solution was generated.")
|
generated_at: DateTime = Field(
|
||||||
|
..., json_schema_extra={"description": "Timestamp when the solution was generated."}
|
||||||
|
)
|
||||||
|
|
||||||
comment: Optional[str] = Field(
|
comment: Optional[str] = Field(
|
||||||
default=None, description="Optional comment or annotation for the solution."
|
default=None,
|
||||||
|
json_schema_extra={"description": "Optional comment or annotation for the solution."},
|
||||||
)
|
)
|
||||||
|
|
||||||
valid_from: Optional[DateTime] = Field(
|
valid_from: Optional[DateTime] = Field(
|
||||||
default=None, description="Start time of the optimization solution."
|
default=None, json_schema_extra={"description": "Start time of the optimization solution."}
|
||||||
)
|
)
|
||||||
|
|
||||||
valid_until: Optional[DateTime] = Field(
|
valid_until: Optional[DateTime] = Field(
|
||||||
default=None,
|
default=None, json_schema_extra={"description": "End time of the optimization solution."}
|
||||||
description="End time of the optimization solution.",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
total_losses_energy_wh: float = Field(
|
total_losses_energy_wh: float = Field(
|
||||||
description="The total losses in watt-hours over the entire period."
|
json_schema_extra={"description": "The total losses in watt-hours over the entire period."}
|
||||||
)
|
)
|
||||||
|
|
||||||
total_revenues_amt: float = Field(description="The total revenues [money amount].")
|
total_revenues_amt: float = Field(
|
||||||
|
json_schema_extra={"description": "The total revenues [money amount]."}
|
||||||
|
)
|
||||||
|
|
||||||
total_costs_amt: float = Field(description="The total costs [money amount].")
|
total_costs_amt: float = Field(
|
||||||
|
json_schema_extra={"description": "The total costs [money amount]."}
|
||||||
|
)
|
||||||
|
|
||||||
fitness_score: set[float] = Field(description="The fitness score as a set of fitness values.")
|
fitness_score: set[float] = Field(
|
||||||
|
json_schema_extra={"description": "The fitness score as a set of fitness values."}
|
||||||
|
)
|
||||||
|
|
||||||
prediction: PydanticDateTimeDataFrame = Field(
|
prediction: PydanticDateTimeDataFrame = Field(
|
||||||
description=(
|
json_schema_extra={
|
||||||
|
"description": (
|
||||||
"Datetime data frame with time series prediction data per optimization interval:"
|
"Datetime data frame with time series prediction data per optimization interval:"
|
||||||
"- pv_energy_wh: PV energy prediction (positive) in wh"
|
"- pv_energy_wh: PV energy prediction (positive) in wh"
|
||||||
"- elec_price_amt_kwh: Electricity price prediction in money per kwh"
|
"- elec_price_amt_kwh: Electricity price prediction in money per kwh"
|
||||||
@@ -123,10 +147,12 @@ class OptimizationSolution(PydanticBaseModel):
|
|||||||
"- loadakkudoktor_std_energy_wh: Load energy standard deviation prediction in wh"
|
"- loadakkudoktor_std_energy_wh: Load energy standard deviation prediction in wh"
|
||||||
"- loadakkudoktor_mean_energy_wh: Load mean energy prediction in wh"
|
"- loadakkudoktor_mean_energy_wh: Load mean energy prediction in wh"
|
||||||
)
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
solution: PydanticDateTimeDataFrame = Field(
|
solution: PydanticDateTimeDataFrame = Field(
|
||||||
description=(
|
json_schema_extra={
|
||||||
|
"description": (
|
||||||
"Datetime data frame with time series solution data per optimization interval:"
|
"Datetime data frame with time series solution data per optimization interval:"
|
||||||
"- load_energy_wh: Load of all energy consumers in wh"
|
"- load_energy_wh: Load of all energy consumers in wh"
|
||||||
"- grid_energy_wh: Grid energy feed in (negative) or consumption (positive) in wh"
|
"- grid_energy_wh: Grid energy feed in (negative) or consumption (positive) in wh"
|
||||||
@@ -138,4 +164,5 @@ class OptimizationSolution(PydanticBaseModel):
|
|||||||
"- <device-id>_soc_factor: State of charge of a battery/ electric vehicle device as factor of total capacity."
|
"- <device-id>_soc_factor: State of charge of a battery/ electric vehicle device as factor of total capacity."
|
||||||
"- <device-id>_energy_wh: Energy consumption (positive) of a device in wh."
|
"- <device-id>_energy_wh: Energy consumption (positive) of a device in wh."
|
||||||
)
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ class ElecPriceCommonProviderSettings(SettingsBaseModel):
|
|||||||
"""Electricity Price Prediction Provider Configuration."""
|
"""Electricity Price Prediction Provider Configuration."""
|
||||||
|
|
||||||
ElecPriceImport: Optional[ElecPriceImportCommonSettings] = Field(
|
ElecPriceImport: Optional[ElecPriceImportCommonSettings] = Field(
|
||||||
default=None, description="ElecPriceImport settings", examples=[None]
|
default=None,
|
||||||
|
json_schema_extra={"description": "ElecPriceImport settings", "examples": [None]},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -30,31 +31,39 @@ class ElecPriceCommonSettings(SettingsBaseModel):
|
|||||||
|
|
||||||
provider: Optional[str] = Field(
|
provider: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Electricity price provider id of provider to be used.",
|
json_schema_extra={
|
||||||
examples=["ElecPriceAkkudoktor"],
|
"description": "Electricity price provider id of provider to be used.",
|
||||||
|
"examples": ["ElecPriceAkkudoktor"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
charges_kwh: Optional[float] = Field(
|
charges_kwh: Optional[float] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
ge=0,
|
ge=0,
|
||||||
description="Electricity price charges [€/kWh]. Will be added to variable market price.",
|
json_schema_extra={
|
||||||
examples=[0.21],
|
"description": "Electricity price charges [€/kWh]. Will be added to variable market price.",
|
||||||
|
"examples": [0.21],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
vat_rate: Optional[float] = Field(
|
vat_rate: Optional[float] = Field(
|
||||||
default=1.19,
|
default=1.19,
|
||||||
ge=0,
|
ge=0,
|
||||||
description="VAT rate factor applied to electricity price when charges are used.",
|
json_schema_extra={
|
||||||
examples=[1.19],
|
"description": "VAT rate factor applied to electricity price when charges are used.",
|
||||||
|
"examples": [1.19],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
provider_settings: ElecPriceCommonProviderSettings = Field(
|
provider_settings: ElecPriceCommonProviderSettings = Field(
|
||||||
default_factory=ElecPriceCommonProviderSettings,
|
default_factory=ElecPriceCommonProviderSettings,
|
||||||
description="Provider settings",
|
json_schema_extra={
|
||||||
examples=[
|
"description": "Provider settings",
|
||||||
|
"examples": [
|
||||||
# Example 1: Empty/default settings (all providers None)
|
# Example 1: Empty/default settings (all providers None)
|
||||||
{
|
{
|
||||||
"ElecPriceImport": None,
|
"ElecPriceImport": None,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validators
|
# Validators
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class ElecPriceDataRecord(PredictionRecord):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
elecprice_marketprice_wh: Optional[float] = Field(
|
elecprice_marketprice_wh: Optional[float] = Field(
|
||||||
None, description="Electricity market price per Wh (€/Wh)"
|
None, json_schema_extra={"description": "Electricity market price per Wh (€/Wh)"}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Computed fields
|
# Computed fields
|
||||||
@@ -59,7 +59,8 @@ class ElecPriceProvider(PredictionProvider):
|
|||||||
|
|
||||||
# overload
|
# overload
|
||||||
records: List[ElecPriceDataRecord] = Field(
|
records: List[ElecPriceDataRecord] = Field(
|
||||||
default_factory=list, description="List of ElecPriceDataRecord records"
|
default_factory=list,
|
||||||
|
json_schema_extra={"description": "List of ElecPriceDataRecord records"},
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -22,14 +22,18 @@ class ElecPriceImportCommonSettings(SettingsBaseModel):
|
|||||||
|
|
||||||
import_file_path: Optional[Union[str, Path]] = Field(
|
import_file_path: Optional[Union[str, Path]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Path to the file to import elecprice data from.",
|
json_schema_extra={
|
||||||
examples=[None, "/path/to/prices.json"],
|
"description": "Path to the file to import elecprice data from.",
|
||||||
|
"examples": [None, "/path/to/prices.json"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
import_json: Optional[str] = Field(
|
import_json: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="JSON string, dictionary of electricity price forecast value lists.",
|
json_schema_extra={
|
||||||
examples=['{"elecprice_marketprice_wh": [0.0003384, 0.0003318, 0.0003284]}'],
|
"description": "JSON string, dictionary of electricity price forecast value lists.",
|
||||||
|
"examples": ['{"elecprice_marketprice_wh": [0.0003384, 0.0003318, 0.0003284]}'],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validators
|
# Validators
|
||||||
|
|||||||
@@ -22,10 +22,12 @@ class FeedInTariffCommonProviderSettings(SettingsBaseModel):
|
|||||||
"""Feed In Tariff Prediction Provider Configuration."""
|
"""Feed In Tariff Prediction Provider Configuration."""
|
||||||
|
|
||||||
FeedInTariffFixed: Optional[FeedInTariffFixedCommonSettings] = Field(
|
FeedInTariffFixed: Optional[FeedInTariffFixedCommonSettings] = Field(
|
||||||
default=None, description="FeedInTariffFixed settings", examples=[None]
|
default=None,
|
||||||
|
json_schema_extra={"description": "FeedInTariffFixed settings", "examples": [None]},
|
||||||
)
|
)
|
||||||
FeedInTariffImport: Optional[FeedInTariffImportCommonSettings] = Field(
|
FeedInTariffImport: Optional[FeedInTariffImportCommonSettings] = Field(
|
||||||
default=None, description="FeedInTariffImport settings", examples=[None]
|
default=None,
|
||||||
|
json_schema_extra={"description": "FeedInTariffImport settings", "examples": [None]},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -34,20 +36,24 @@ class FeedInTariffCommonSettings(SettingsBaseModel):
|
|||||||
|
|
||||||
provider: Optional[str] = Field(
|
provider: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Feed in tariff provider id of provider to be used.",
|
json_schema_extra={
|
||||||
examples=["FeedInTariffFixed", "FeedInTarifImport"],
|
"description": "Feed in tariff provider id of provider to be used.",
|
||||||
|
"examples": ["FeedInTariffFixed", "FeedInTarifImport"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
provider_settings: FeedInTariffCommonProviderSettings = Field(
|
provider_settings: FeedInTariffCommonProviderSettings = Field(
|
||||||
default_factory=FeedInTariffCommonProviderSettings,
|
default_factory=FeedInTariffCommonProviderSettings,
|
||||||
description="Provider settings",
|
json_schema_extra={
|
||||||
examples=[
|
"description": "Provider settings",
|
||||||
|
"examples": [
|
||||||
# Example 1: Empty/default settings (all providers None)
|
# Example 1: Empty/default settings (all providers None)
|
||||||
{
|
{
|
||||||
"FeedInTariffFixed": None,
|
"FeedInTariffFixed": None,
|
||||||
"FeedInTariffImport": None,
|
"FeedInTariffImport": None,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validators
|
# Validators
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ class FeedInTariffDataRecord(PredictionRecord):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
feed_in_tariff_wh: Optional[float] = Field(None, description="Feed in tariff per Wh (€/Wh)")
|
feed_in_tariff_wh: Optional[float] = Field(
|
||||||
|
None, json_schema_extra={"description": "Feed in tariff per Wh (€/Wh)"}
|
||||||
|
)
|
||||||
|
|
||||||
# Computed fields
|
# Computed fields
|
||||||
@computed_field # type: ignore[prop-decorator]
|
@computed_field # type: ignore[prop-decorator]
|
||||||
@@ -46,7 +48,8 @@ class FeedInTariffProvider(PredictionProvider):
|
|||||||
|
|
||||||
# overload
|
# overload
|
||||||
records: List[FeedInTariffDataRecord] = Field(
|
records: List[FeedInTariffDataRecord] = Field(
|
||||||
default_factory=list, description="List of FeedInTariffDataRecord records"
|
default_factory=list,
|
||||||
|
json_schema_extra={"description": "List of FeedInTariffDataRecord records"},
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -16,8 +16,10 @@ class FeedInTariffFixedCommonSettings(SettingsBaseModel):
|
|||||||
feed_in_tariff_kwh: Optional[float] = Field(
|
feed_in_tariff_kwh: Optional[float] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
ge=0,
|
ge=0,
|
||||||
description="Electricity price feed in tariff [€/kWH].",
|
json_schema_extra={
|
||||||
examples=[0.078],
|
"description": "Electricity price feed in tariff [€/kWH].",
|
||||||
|
"examples": [0.078],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,13 +21,17 @@ class FeedInTariffImportCommonSettings(SettingsBaseModel):
|
|||||||
|
|
||||||
import_file_path: Optional[Union[str, Path]] = Field(
|
import_file_path: Optional[Union[str, Path]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Path to the file to import feed in tariff data from.",
|
json_schema_extra={
|
||||||
examples=[None, "/path/to/feedintariff.json"],
|
"description": "Path to the file to import feed in tariff data from.",
|
||||||
|
"examples": [None, "/path/to/feedintariff.json"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
import_json: Optional[str] = Field(
|
import_json: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="JSON string, dictionary of feed in tariff forecast value lists.",
|
json_schema_extra={
|
||||||
examples=['{"fead_in_tariff_wh": [0.000078, 0.000078, 0.000023]}'],
|
"description": "JSON string, dictionary of feed in tariff forecast value lists.",
|
||||||
|
"examples": ['{"fead_in_tariff_wh": [0.000078, 0.000078, 0.000023]}'],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validators
|
# Validators
|
||||||
|
|||||||
@@ -25,13 +25,14 @@ class LoadCommonProviderSettings(SettingsBaseModel):
|
|||||||
"""Load Prediction Provider Configuration."""
|
"""Load Prediction Provider Configuration."""
|
||||||
|
|
||||||
LoadAkkudoktor: Optional[LoadAkkudoktorCommonSettings] = Field(
|
LoadAkkudoktor: Optional[LoadAkkudoktorCommonSettings] = Field(
|
||||||
default=None, description="LoadAkkudoktor settings", examples=[None]
|
default=None,
|
||||||
|
json_schema_extra={"description": "LoadAkkudoktor settings", "examples": [None]},
|
||||||
)
|
)
|
||||||
LoadVrm: Optional[LoadVrmCommonSettings] = Field(
|
LoadVrm: Optional[LoadVrmCommonSettings] = Field(
|
||||||
default=None, description="LoadVrm settings", examples=[None]
|
default=None, json_schema_extra={"description": "LoadVrm settings", "examples": [None]}
|
||||||
)
|
)
|
||||||
LoadImport: Optional[LoadImportCommonSettings] = Field(
|
LoadImport: Optional[LoadImportCommonSettings] = Field(
|
||||||
default=None, description="LoadImport settings", examples=[None]
|
default=None, json_schema_extra={"description": "LoadImport settings", "examples": [None]}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -40,14 +41,17 @@ class LoadCommonSettings(SettingsBaseModel):
|
|||||||
|
|
||||||
provider: Optional[str] = Field(
|
provider: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Load provider id of provider to be used.",
|
json_schema_extra={
|
||||||
examples=["LoadAkkudoktor"],
|
"description": "Load provider id of provider to be used.",
|
||||||
|
"examples": ["LoadAkkudoktor"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
provider_settings: LoadCommonProviderSettings = Field(
|
provider_settings: LoadCommonProviderSettings = Field(
|
||||||
default_factory=LoadCommonProviderSettings,
|
default_factory=LoadCommonProviderSettings,
|
||||||
description="Provider settings",
|
json_schema_extra={
|
||||||
examples=[
|
"description": "Provider settings",
|
||||||
|
"examples": [
|
||||||
# Example 1: Empty/default settings (all providers None)
|
# Example 1: Empty/default settings (all providers None)
|
||||||
{
|
{
|
||||||
"LoadAkkudoktor": None,
|
"LoadAkkudoktor": None,
|
||||||
@@ -55,6 +59,7 @@ class LoadCommonSettings(SettingsBaseModel):
|
|||||||
"LoadImport": None,
|
"LoadImport": None,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validators
|
# Validators
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class LoadDataRecord(PredictionRecord):
|
|||||||
"""Represents a load data record containing various load attributes at a specific datetime."""
|
"""Represents a load data record containing various load attributes at a specific datetime."""
|
||||||
|
|
||||||
loadforecast_power_w: Optional[float] = Field(
|
loadforecast_power_w: Optional[float] = Field(
|
||||||
default=None, description="Predicted load mean value (W)."
|
default=None, json_schema_extra={"description": "Predicted load mean value (W)."}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ class LoadProvider(PredictionProvider):
|
|||||||
|
|
||||||
# overload
|
# overload
|
||||||
records: List[LoadDataRecord] = Field(
|
records: List[LoadDataRecord] = Field(
|
||||||
default_factory=list, description="List of LoadDataRecord records"
|
default_factory=list, json_schema_extra={"description": "List of LoadDataRecord records"}
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ class LoadAkkudoktorCommonSettings(SettingsBaseModel):
|
|||||||
"""Common settings for load data import from file."""
|
"""Common settings for load data import from file."""
|
||||||
|
|
||||||
loadakkudoktor_year_energy_kwh: Optional[float] = Field(
|
loadakkudoktor_year_energy_kwh: Optional[float] = Field(
|
||||||
default=None, description="Yearly energy consumption (kWh).", examples=[40421]
|
default=None,
|
||||||
|
json_schema_extra={"description": "Yearly energy consumption (kWh).", "examples": [40421]},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -23,11 +24,11 @@ class LoadAkkudoktorDataRecord(LoadDataRecord):
|
|||||||
"""Represents a load data record with extra fields for LoadAkkudoktor."""
|
"""Represents a load data record with extra fields for LoadAkkudoktor."""
|
||||||
|
|
||||||
loadakkudoktor_mean_power_w: Optional[float] = Field(
|
loadakkudoktor_mean_power_w: Optional[float] = Field(
|
||||||
default=None, description="Predicted load mean value (W)."
|
default=None, json_schema_extra={"description": "Predicted load mean value (W)."}
|
||||||
)
|
)
|
||||||
|
|
||||||
loadakkudoktor_std_power_w: Optional[float] = Field(
|
loadakkudoktor_std_power_w: Optional[float] = Field(
|
||||||
default=None, description="Predicted load standard deviation (W)."
|
default=None, json_schema_extra={"description": "Predicted load standard deviation (W)."}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -35,7 +36,8 @@ class LoadAkkudoktor(LoadProvider):
|
|||||||
"""Fetch Load forecast data from Akkudoktor load profiles."""
|
"""Fetch Load forecast data from Akkudoktor load profiles."""
|
||||||
|
|
||||||
records: list[LoadAkkudoktorDataRecord] = Field(
|
records: list[LoadAkkudoktorDataRecord] = Field(
|
||||||
default_factory=list, description="List of LoadAkkudoktorDataRecord records"
|
default_factory=list,
|
||||||
|
json_schema_extra={"description": "List of LoadAkkudoktorDataRecord records"},
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -22,13 +22,17 @@ class LoadImportCommonSettings(SettingsBaseModel):
|
|||||||
|
|
||||||
import_file_path: Optional[Union[str, Path]] = Field(
|
import_file_path: Optional[Union[str, Path]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Path to the file to import load data from.",
|
json_schema_extra={
|
||||||
examples=[None, "/path/to/yearly_load.json"],
|
"description": "Path to the file to import load data from.",
|
||||||
|
"examples": [None, "/path/to/yearly_load.json"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
import_json: Optional[str] = Field(
|
import_json: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="JSON string, dictionary of load forecast value lists.",
|
json_schema_extra={
|
||||||
examples=['{"load0_mean": [676.71, 876.19, 527.13]}'],
|
"description": "JSON string, dictionary of load forecast value lists.",
|
||||||
|
"examples": ['{"load0_mean": [676.71, 876.19, 527.13]}'],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validators
|
# Validators
|
||||||
|
|||||||
@@ -27,9 +27,15 @@ class LoadVrmCommonSettings(SettingsBaseModel):
|
|||||||
"""Common settings for VRM API."""
|
"""Common settings for VRM API."""
|
||||||
|
|
||||||
load_vrm_token: str = Field(
|
load_vrm_token: str = Field(
|
||||||
default="your-token", description="Token for Connecting VRM API", examples=["your-token"]
|
default="your-token",
|
||||||
|
json_schema_extra={
|
||||||
|
"description": "Token for Connecting VRM API",
|
||||||
|
"examples": ["your-token"],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
load_vrm_idsite: int = Field(
|
||||||
|
default=12345, json_schema_extra={"description": "VRM-Installation-ID", "examples": [12345]}
|
||||||
)
|
)
|
||||||
load_vrm_idsite: int = Field(default=12345, description="VRM-Installation-ID", examples=[12345])
|
|
||||||
|
|
||||||
|
|
||||||
class LoadVrm(LoadProvider):
|
class LoadVrm(LoadProvider):
|
||||||
|
|||||||
@@ -70,13 +70,17 @@ class PredictionCommonSettings(SettingsBaseModel):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
hours: Optional[int] = Field(
|
hours: Optional[int] = Field(
|
||||||
default=48, ge=0, description="Number of hours into the future for predictions"
|
default=48,
|
||||||
|
ge=0,
|
||||||
|
json_schema_extra={"description": "Number of hours into the future for predictions"},
|
||||||
)
|
)
|
||||||
|
|
||||||
historic_hours: Optional[int] = Field(
|
historic_hours: Optional[int] = Field(
|
||||||
default=48,
|
default=48,
|
||||||
ge=0,
|
ge=0,
|
||||||
description="Number of hours into the past for historical predictions data",
|
json_schema_extra={
|
||||||
|
"description": "Number of hours into the past for historical predictions data"
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -107,7 +111,9 @@ class Prediction(PredictionContainer):
|
|||||||
WeatherClearOutside,
|
WeatherClearOutside,
|
||||||
WeatherImport,
|
WeatherImport,
|
||||||
]
|
]
|
||||||
] = Field(default_factory=list, description="List of prediction providers")
|
] = Field(
|
||||||
|
default_factory=list, json_schema_extra={"description": "List of prediction providers"}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Initialize forecast providers, all are singletons.
|
# Initialize forecast providers, all are singletons.
|
||||||
|
|||||||
@@ -72,8 +72,7 @@ class PredictionSequence(DataSequence):
|
|||||||
Usage:
|
Usage:
|
||||||
# Example of creating, adding, and using PredictionSequence
|
# Example of creating, adding, and using PredictionSequence
|
||||||
class DerivedSequence(PredictionSquence):
|
class DerivedSequence(PredictionSquence):
|
||||||
records: List[DerivedPredictionRecord] = Field(default_factory=list,
|
records: List[DerivedPredictionRecord] = Field(default_factory=list, json_schema_extra={ "description": "List of prediction records" })
|
||||||
description="List of prediction records")
|
|
||||||
|
|
||||||
seq = DerivedSequence()
|
seq = DerivedSequence()
|
||||||
seq.insert(DerivedPredictionRecord(date_time=datetime.now(), temperature=72))
|
seq.insert(DerivedPredictionRecord(date_time=datetime.now(), temperature=72))
|
||||||
@@ -89,7 +88,7 @@ class PredictionSequence(DataSequence):
|
|||||||
|
|
||||||
# To be overloaded by derived classes.
|
# To be overloaded by derived classes.
|
||||||
records: List[PredictionRecord] = Field(
|
records: List[PredictionRecord] = Field(
|
||||||
default_factory=list, description="List of prediction records"
|
default_factory=list, json_schema_extra={"description": "List of prediction records"}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -249,5 +248,5 @@ class PredictionContainer(PredictionStartEndKeepMixin, DataContainer):
|
|||||||
|
|
||||||
# To be overloaded by derived classes.
|
# To be overloaded by derived classes.
|
||||||
providers: List[PredictionProvider] = Field(
|
providers: List[PredictionProvider] = Field(
|
||||||
default_factory=list, description="List of prediction providers"
|
default_factory=list, json_schema_extra={"description": "List of prediction providers"}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -23,77 +23,118 @@ pvforecast_providers = [
|
|||||||
class PVForecastPlaneSetting(SettingsBaseModel):
|
class PVForecastPlaneSetting(SettingsBaseModel):
|
||||||
"""PV Forecast Plane Configuration."""
|
"""PV Forecast Plane Configuration."""
|
||||||
|
|
||||||
# latitude: Optional[float] = Field(default=None, description="Latitude in decimal degrees, between -90 and 90, north is positive (ISO 19115) (°)")
|
# latitude: Optional[float] = Field(default=None, json_schema_extra={ "description": "Latitude in decimal degrees, between -90 and 90, north is positive (ISO 19115) (°)" })
|
||||||
surface_tilt: Optional[float] = Field(
|
surface_tilt: Optional[float] = Field(
|
||||||
default=30.0,
|
default=30.0,
|
||||||
ge=0.0,
|
ge=0.0,
|
||||||
le=90.0,
|
le=90.0,
|
||||||
description="Tilt angle from horizontal plane. Ignored for two-axis tracking.",
|
json_schema_extra={
|
||||||
examples=[10.0, 20.0],
|
"description": "Tilt angle from horizontal plane. Ignored for two-axis tracking.",
|
||||||
|
"examples": [10.0, 20.0],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
surface_azimuth: Optional[float] = Field(
|
surface_azimuth: Optional[float] = Field(
|
||||||
default=180.0,
|
default=180.0,
|
||||||
ge=0.0,
|
ge=0.0,
|
||||||
le=360.0,
|
le=360.0,
|
||||||
description="Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).",
|
json_schema_extra={
|
||||||
examples=[180.0, 90.0],
|
"description": "Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).",
|
||||||
|
"examples": [180.0, 90.0],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
userhorizon: Optional[List[float]] = Field(
|
userhorizon: Optional[List[float]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.",
|
json_schema_extra={
|
||||||
examples=[[10.0, 20.0, 30.0], [5.0, 15.0, 25.0]],
|
"description": "Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.",
|
||||||
|
"examples": [[10.0, 20.0, 30.0], [5.0, 15.0, 25.0]],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
peakpower: Optional[float] = Field(
|
peakpower: Optional[float] = Field(
|
||||||
default=None, description="Nominal power of PV system in kW.", examples=[5.0, 3.5]
|
default=None,
|
||||||
|
json_schema_extra={
|
||||||
|
"description": "Nominal power of PV system in kW.",
|
||||||
|
"examples": [5.0, 3.5],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
pvtechchoice: Optional[str] = Field(
|
pvtechchoice: Optional[str] = Field(
|
||||||
default="crystSi", description="PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'."
|
default="crystSi",
|
||||||
|
json_schema_extra={
|
||||||
|
"description": "PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'."
|
||||||
|
},
|
||||||
)
|
)
|
||||||
mountingplace: Optional[str] = Field(
|
mountingplace: Optional[str] = Field(
|
||||||
default="free",
|
default="free",
|
||||||
description="Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.",
|
json_schema_extra={
|
||||||
|
"description": "Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated."
|
||||||
|
},
|
||||||
|
)
|
||||||
|
loss: Optional[float] = Field(
|
||||||
|
default=14.0, json_schema_extra={"description": "Sum of PV system losses in percent"}
|
||||||
)
|
)
|
||||||
loss: Optional[float] = Field(default=14.0, description="Sum of PV system losses in percent")
|
|
||||||
trackingtype: Optional[int] = Field(
|
trackingtype: Optional[int] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
ge=0,
|
ge=0,
|
||||||
le=5,
|
le=5,
|
||||||
description="Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.",
|
json_schema_extra={
|
||||||
examples=[0, 1, 2, 3, 4, 5],
|
"description": "Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.",
|
||||||
|
"examples": [0, 1, 2, 3, 4, 5],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
optimal_surface_tilt: Optional[bool] = Field(
|
optimal_surface_tilt: Optional[bool] = Field(
|
||||||
default=False,
|
default=False,
|
||||||
description="Calculate the optimum tilt angle. Ignored for two-axis tracking.",
|
json_schema_extra={
|
||||||
examples=[False],
|
"description": "Calculate the optimum tilt angle. Ignored for two-axis tracking.",
|
||||||
|
"examples": [False],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
optimalangles: Optional[bool] = Field(
|
optimalangles: Optional[bool] = Field(
|
||||||
default=False,
|
default=False,
|
||||||
description="Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.",
|
json_schema_extra={
|
||||||
examples=[False],
|
"description": "Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.",
|
||||||
|
"examples": [False],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
albedo: Optional[float] = Field(
|
albedo: Optional[float] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Proportion of the light hitting the ground that it reflects back.",
|
json_schema_extra={
|
||||||
examples=[None],
|
"description": "Proportion of the light hitting the ground that it reflects back.",
|
||||||
|
"examples": [None],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
module_model: Optional[str] = Field(
|
module_model: Optional[str] = Field(
|
||||||
default=None, description="Model of the PV modules of this plane.", examples=[None]
|
default=None,
|
||||||
|
json_schema_extra={
|
||||||
|
"description": "Model of the PV modules of this plane.",
|
||||||
|
"examples": [None],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
inverter_model: Optional[str] = Field(
|
inverter_model: Optional[str] = Field(
|
||||||
default=None, description="Model of the inverter of this plane.", examples=[None]
|
default=None,
|
||||||
|
json_schema_extra={
|
||||||
|
"description": "Model of the inverter of this plane.",
|
||||||
|
"examples": [None],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
inverter_paco: Optional[int] = Field(
|
inverter_paco: Optional[int] = Field(
|
||||||
default=None, description="AC power rating of the inverter [W].", examples=[6000, 4000]
|
default=None,
|
||||||
|
json_schema_extra={
|
||||||
|
"description": "AC power rating of the inverter [W].",
|
||||||
|
"examples": [6000, 4000],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
modules_per_string: Optional[int] = Field(
|
modules_per_string: Optional[int] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Number of the PV modules of the strings of this plane.",
|
json_schema_extra={
|
||||||
examples=[20],
|
"description": "Number of the PV modules of the strings of this plane.",
|
||||||
|
"examples": [20],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
strings_per_inverter: Optional[int] = Field(
|
strings_per_inverter: Optional[int] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Number of the strings of the inverter of this plane.",
|
json_schema_extra={
|
||||||
examples=[2],
|
"description": "Number of the strings of the inverter of this plane.",
|
||||||
|
"examples": [2],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
@@ -124,10 +165,12 @@ class PVForecastCommonProviderSettings(SettingsBaseModel):
|
|||||||
"""PV Forecast Provider Configuration."""
|
"""PV Forecast Provider Configuration."""
|
||||||
|
|
||||||
PVForecastImport: Optional[PVForecastImportCommonSettings] = Field(
|
PVForecastImport: Optional[PVForecastImportCommonSettings] = Field(
|
||||||
default=None, description="PVForecastImport settings", examples=[None]
|
default=None,
|
||||||
|
json_schema_extra={"description": "PVForecastImport settings", "examples": [None]},
|
||||||
)
|
)
|
||||||
PVForecastVrm: Optional[PVForecastVrmCommonSettings] = Field(
|
PVForecastVrm: Optional[PVForecastVrmCommonSettings] = Field(
|
||||||
default=None, description="PVForecastVrm settings", examples=[None]
|
default=None,
|
||||||
|
json_schema_extra={"description": "PVForecastVrm settings", "examples": [None]},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -141,26 +184,31 @@ class PVForecastCommonSettings(SettingsBaseModel):
|
|||||||
|
|
||||||
provider: Optional[str] = Field(
|
provider: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="PVForecast provider id of provider to be used.",
|
json_schema_extra={
|
||||||
examples=["PVForecastAkkudoktor"],
|
"description": "PVForecast provider id of provider to be used.",
|
||||||
|
"examples": ["PVForecastAkkudoktor"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
provider_settings: PVForecastCommonProviderSettings = Field(
|
provider_settings: PVForecastCommonProviderSettings = Field(
|
||||||
default_factory=PVForecastCommonProviderSettings,
|
default_factory=PVForecastCommonProviderSettings,
|
||||||
description="Provider settings",
|
json_schema_extra={
|
||||||
examples=[
|
"description": "Provider settings",
|
||||||
|
"examples": [
|
||||||
# Example 1: Empty/default settings (all providers None)
|
# Example 1: Empty/default settings (all providers None)
|
||||||
{
|
{
|
||||||
"PVForecastImport": None,
|
"PVForecastImport": None,
|
||||||
"PVForecastVrm": None,
|
"PVForecastVrm": None,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
planes: Optional[list[PVForecastPlaneSetting]] = Field(
|
planes: Optional[list[PVForecastPlaneSetting]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Plane configuration.",
|
json_schema_extra={
|
||||||
examples=[
|
"description": "Plane configuration.",
|
||||||
|
"examples": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"surface_tilt": 10.0,
|
"surface_tilt": 10.0,
|
||||||
@@ -200,13 +248,16 @@ class PVForecastCommonSettings(SettingsBaseModel):
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
max_planes: Optional[int] = Field(
|
max_planes: Optional[int] = Field(
|
||||||
default=0,
|
default=0,
|
||||||
ge=0,
|
ge=0,
|
||||||
description="Maximum number of planes that can be set",
|
json_schema_extra={
|
||||||
examples=[1, 2],
|
"description": "Maximum number of planes that can be set",
|
||||||
|
"examples": [1, 2],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validators
|
# Validators
|
||||||
|
|||||||
@@ -16,8 +16,12 @@ from akkudoktoreos.prediction.predictionabc import PredictionProvider, Predictio
|
|||||||
class PVForecastDataRecord(PredictionRecord):
|
class PVForecastDataRecord(PredictionRecord):
|
||||||
"""Represents a pvforecast data record containing various pvforecast attributes at a specific datetime."""
|
"""Represents a pvforecast data record containing various pvforecast attributes at a specific datetime."""
|
||||||
|
|
||||||
pvforecast_dc_power: Optional[float] = Field(default=None, description="Total DC power (W).")
|
pvforecast_dc_power: Optional[float] = Field(
|
||||||
pvforecast_ac_power: Optional[float] = Field(default=None, description="Total AC power (W).")
|
default=None, json_schema_extra={"description": "Total DC power (W)."}
|
||||||
|
)
|
||||||
|
pvforecast_ac_power: Optional[float] = Field(
|
||||||
|
default=None, json_schema_extra={"description": "Total AC power (W)."}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PVForecastProvider(PredictionProvider):
|
class PVForecastProvider(PredictionProvider):
|
||||||
@@ -42,7 +46,8 @@ class PVForecastProvider(PredictionProvider):
|
|||||||
|
|
||||||
# overload
|
# overload
|
||||||
records: List[PVForecastDataRecord] = Field(
|
records: List[PVForecastDataRecord] = Field(
|
||||||
default_factory=list, description="List of PVForecastDataRecord records"
|
default_factory=list,
|
||||||
|
json_schema_extra={"description": "List of PVForecastDataRecord records"},
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -157,13 +157,13 @@ class PVForecastAkkudoktorDataRecord(PVForecastDataRecord):
|
|||||||
"""Represents a Akkudoktor specific pvforecast data record containing various pvforecast attributes at a specific datetime."""
|
"""Represents a Akkudoktor specific pvforecast data record containing various pvforecast attributes at a specific datetime."""
|
||||||
|
|
||||||
pvforecastakkudoktor_ac_power_measured: Optional[float] = Field(
|
pvforecastakkudoktor_ac_power_measured: Optional[float] = Field(
|
||||||
default=None, description="Total AC power measured (W)"
|
default=None, json_schema_extra={"description": "Total AC power measured (W)"}
|
||||||
)
|
)
|
||||||
pvforecastakkudoktor_wind_speed_10m: Optional[float] = Field(
|
pvforecastakkudoktor_wind_speed_10m: Optional[float] = Field(
|
||||||
default=None, description="Wind Speed 10m (kmph)"
|
default=None, json_schema_extra={"description": "Wind Speed 10m (kmph)"}
|
||||||
)
|
)
|
||||||
pvforecastakkudoktor_temp_air: Optional[float] = Field(
|
pvforecastakkudoktor_temp_air: Optional[float] = Field(
|
||||||
default=None, description="Temperature (°C)"
|
default=None, json_schema_extra={"description": "Temperature (°C)"}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Computed fields
|
# Computed fields
|
||||||
@@ -209,7 +209,8 @@ class PVForecastAkkudoktor(PVForecastProvider):
|
|||||||
|
|
||||||
# overload
|
# overload
|
||||||
records: List[PVForecastAkkudoktorDataRecord] = Field(
|
records: List[PVForecastAkkudoktorDataRecord] = Field(
|
||||||
default_factory=list, description="List of PVForecastAkkudoktorDataRecord records"
|
default_factory=list,
|
||||||
|
json_schema_extra={"description": "List of PVForecastAkkudoktorDataRecord records"},
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -22,14 +22,18 @@ class PVForecastImportCommonSettings(SettingsBaseModel):
|
|||||||
|
|
||||||
import_file_path: Optional[Union[str, Path]] = Field(
|
import_file_path: Optional[Union[str, Path]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Path to the file to import PV forecast data from.",
|
json_schema_extra={
|
||||||
examples=[None, "/path/to/pvforecast.json"],
|
"description": "Path to the file to import PV forecast data from.",
|
||||||
|
"examples": [None, "/path/to/pvforecast.json"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
import_json: Optional[str] = Field(
|
import_json: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="JSON string, dictionary of PV forecast value lists.",
|
json_schema_extra={
|
||||||
examples=['{"pvforecast_ac_power": [0, 8.05, 352.91]}'],
|
"description": "JSON string, dictionary of PV forecast value lists.",
|
||||||
|
"examples": ['{"pvforecast_ac_power": [0, 8.05, 352.91]}'],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validators
|
# Validators
|
||||||
|
|||||||
@@ -27,10 +27,14 @@ class PVForecastVrmCommonSettings(SettingsBaseModel):
|
|||||||
"""Common settings for VRM API."""
|
"""Common settings for VRM API."""
|
||||||
|
|
||||||
pvforecast_vrm_token: str = Field(
|
pvforecast_vrm_token: str = Field(
|
||||||
default="your-token", description="Token for Connecting VRM API", examples=["your-token"]
|
default="your-token",
|
||||||
|
json_schema_extra={
|
||||||
|
"description": "Token for Connecting VRM API",
|
||||||
|
"examples": ["your-token"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
pvforecast_vrm_idsite: int = Field(
|
pvforecast_vrm_idsite: int = Field(
|
||||||
default=12345, description="VRM-Installation-ID", examples=[12345]
|
default=12345, json_schema_extra={"description": "VRM-Installation-ID", "examples": [12345]}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ class WeatherCommonProviderSettings(SettingsBaseModel):
|
|||||||
"""Weather Forecast Provider Configuration."""
|
"""Weather Forecast Provider Configuration."""
|
||||||
|
|
||||||
WeatherImport: Optional[WeatherImportCommonSettings] = Field(
|
WeatherImport: Optional[WeatherImportCommonSettings] = Field(
|
||||||
default=None, description="WeatherImport settings", examples=[None]
|
default=None,
|
||||||
|
json_schema_extra={"description": "WeatherImport settings", "examples": [None]},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -32,19 +33,23 @@ class WeatherCommonSettings(SettingsBaseModel):
|
|||||||
|
|
||||||
provider: Optional[str] = Field(
|
provider: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Weather provider id of provider to be used.",
|
json_schema_extra={
|
||||||
examples=["WeatherImport"],
|
"description": "Weather provider id of provider to be used.",
|
||||||
|
"examples": ["WeatherImport"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
provider_settings: WeatherCommonProviderSettings = Field(
|
provider_settings: WeatherCommonProviderSettings = Field(
|
||||||
default_factory=WeatherCommonProviderSettings,
|
default_factory=WeatherCommonProviderSettings,
|
||||||
description="Provider settings",
|
json_schema_extra={
|
||||||
examples=[
|
"description": "Provider settings",
|
||||||
|
"examples": [
|
||||||
# Example 1: Empty/default settings (all providers None)
|
# Example 1: Empty/default settings (all providers None)
|
||||||
{
|
{
|
||||||
"WeatherImport": None,
|
"WeatherImport": None,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validators
|
# Validators
|
||||||
|
|||||||
@@ -47,48 +47,68 @@ class WeatherDataRecord(PredictionRecord):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
weather_total_clouds: Optional[float] = Field(
|
weather_total_clouds: Optional[float] = Field(
|
||||||
default=None, description="Total Clouds (% Sky Obscured)"
|
default=None, json_schema_extra={"description": "Total Clouds (% Sky Obscured)"}
|
||||||
)
|
)
|
||||||
weather_low_clouds: Optional[float] = Field(
|
weather_low_clouds: Optional[float] = Field(
|
||||||
default=None, description="Low Clouds (% Sky Obscured)"
|
default=None, json_schema_extra={"description": "Low Clouds (% Sky Obscured)"}
|
||||||
)
|
)
|
||||||
weather_medium_clouds: Optional[float] = Field(
|
weather_medium_clouds: Optional[float] = Field(
|
||||||
default=None, description="Medium Clouds (% Sky Obscured)"
|
default=None, json_schema_extra={"description": "Medium Clouds (% Sky Obscured)"}
|
||||||
)
|
)
|
||||||
weather_high_clouds: Optional[float] = Field(
|
weather_high_clouds: Optional[float] = Field(
|
||||||
default=None, description="High Clouds (% Sky Obscured)"
|
default=None, json_schema_extra={"description": "High Clouds (% Sky Obscured)"}
|
||||||
|
)
|
||||||
|
weather_visibility: Optional[float] = Field(
|
||||||
|
default=None, json_schema_extra={"description": "Visibility (m)"}
|
||||||
|
)
|
||||||
|
weather_fog: Optional[float] = Field(default=None, json_schema_extra={"description": "Fog (%)"})
|
||||||
|
weather_precip_type: Optional[str] = Field(
|
||||||
|
default=None, json_schema_extra={"description": "Precipitation Type"}
|
||||||
)
|
)
|
||||||
weather_visibility: Optional[float] = Field(default=None, description="Visibility (m)")
|
|
||||||
weather_fog: Optional[float] = Field(default=None, description="Fog (%)")
|
|
||||||
weather_precip_type: Optional[str] = Field(default=None, description="Precipitation Type")
|
|
||||||
weather_precip_prob: Optional[float] = Field(
|
weather_precip_prob: Optional[float] = Field(
|
||||||
default=None, description="Precipitation Probability (%)"
|
default=None, json_schema_extra={"description": "Precipitation Probability (%)"}
|
||||||
)
|
)
|
||||||
weather_precip_amt: Optional[float] = Field(
|
weather_precip_amt: Optional[float] = Field(
|
||||||
default=None, description="Precipitation Amount (mm)"
|
default=None, json_schema_extra={"description": "Precipitation Amount (mm)"}
|
||||||
)
|
)
|
||||||
weather_preciptable_water: Optional[float] = Field(
|
weather_preciptable_water: Optional[float] = Field(
|
||||||
default=None, description="Precipitable Water (cm)"
|
default=None, json_schema_extra={"description": "Precipitable Water (cm)"}
|
||||||
|
)
|
||||||
|
weather_wind_speed: Optional[float] = Field(
|
||||||
|
default=None, json_schema_extra={"description": "Wind Speed (kmph)"}
|
||||||
|
)
|
||||||
|
weather_wind_direction: Optional[float] = Field(
|
||||||
|
default=None, json_schema_extra={"description": "Wind Direction (°)"}
|
||||||
|
)
|
||||||
|
weather_frost_chance: Optional[str] = Field(
|
||||||
|
default=None, json_schema_extra={"description": "Chance of Frost"}
|
||||||
|
)
|
||||||
|
weather_temp_air: Optional[float] = Field(
|
||||||
|
default=None, json_schema_extra={"description": "Temperature (°C)"}
|
||||||
|
)
|
||||||
|
weather_feels_like: Optional[float] = Field(
|
||||||
|
default=None, json_schema_extra={"description": "Feels Like (°C)"}
|
||||||
|
)
|
||||||
|
weather_dew_point: Optional[float] = Field(
|
||||||
|
default=None, json_schema_extra={"description": "Dew Point (°C)"}
|
||||||
)
|
)
|
||||||
weather_wind_speed: Optional[float] = Field(default=None, description="Wind Speed (kmph)")
|
|
||||||
weather_wind_direction: Optional[float] = Field(default=None, description="Wind Direction (°)")
|
|
||||||
weather_frost_chance: Optional[str] = Field(default=None, description="Chance of Frost")
|
|
||||||
weather_temp_air: Optional[float] = Field(default=None, description="Temperature (°C)")
|
|
||||||
weather_feels_like: Optional[float] = Field(default=None, description="Feels Like (°C)")
|
|
||||||
weather_dew_point: Optional[float] = Field(default=None, description="Dew Point (°C)")
|
|
||||||
weather_relative_humidity: Optional[float] = Field(
|
weather_relative_humidity: Optional[float] = Field(
|
||||||
default=None, description="Relative Humidity (%)"
|
default=None, json_schema_extra={"description": "Relative Humidity (%)"}
|
||||||
|
)
|
||||||
|
weather_pressure: Optional[float] = Field(
|
||||||
|
default=None, json_schema_extra={"description": "Pressure (mb)"}
|
||||||
|
)
|
||||||
|
weather_ozone: Optional[float] = Field(
|
||||||
|
default=None, json_schema_extra={"description": "Ozone (du)"}
|
||||||
)
|
)
|
||||||
weather_pressure: Optional[float] = Field(default=None, description="Pressure (mb)")
|
|
||||||
weather_ozone: Optional[float] = Field(default=None, description="Ozone (du)")
|
|
||||||
weather_ghi: Optional[float] = Field(
|
weather_ghi: Optional[float] = Field(
|
||||||
default=None, description="Global Horizontal Irradiance (W/m2)"
|
default=None, json_schema_extra={"description": "Global Horizontal Irradiance (W/m2)"}
|
||||||
)
|
)
|
||||||
weather_dni: Optional[float] = Field(
|
weather_dni: Optional[float] = Field(
|
||||||
default=None, description="Direct Normal Irradiance (W/m2)"
|
default=None, json_schema_extra={"description": "Direct Normal Irradiance (W/m2)"}
|
||||||
)
|
)
|
||||||
weather_dhi: Optional[float] = Field(
|
weather_dhi: Optional[float] = Field(
|
||||||
default=None, description="Diffuse Horizontal Irradiance (W/m2)"
|
default=None, json_schema_extra={"description": "Diffuse Horizontal Irradiance (W/m2)"}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -114,7 +134,7 @@ class WeatherProvider(PredictionProvider):
|
|||||||
|
|
||||||
# overload
|
# overload
|
||||||
records: List[WeatherDataRecord] = Field(
|
records: List[WeatherDataRecord] = Field(
|
||||||
default_factory=list, description="List of WeatherDataRecord records"
|
default_factory=list, json_schema_extra={"description": "List of WeatherDataRecord records"}
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -22,14 +22,18 @@ class WeatherImportCommonSettings(SettingsBaseModel):
|
|||||||
|
|
||||||
import_file_path: Optional[Union[str, Path]] = Field(
|
import_file_path: Optional[Union[str, Path]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Path to the file to import weather data from.",
|
json_schema_extra={
|
||||||
examples=[None, "/path/to/weather_data.json"],
|
"description": "Path to the file to import weather data from.",
|
||||||
|
"examples": [None, "/path/to/weather_data.json"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
import_json: Optional[str] = Field(
|
import_json: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="JSON string, dictionary of weather forecast value lists.",
|
json_schema_extra={
|
||||||
examples=['{"weather_temp_air": [18.3, 17.8, 16.9]}'],
|
"description": "JSON string, dictionary of weather forecast value lists.",
|
||||||
|
"examples": ['{"weather_temp_air": [18.3, 17.8, 16.9]}'],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validators
|
# Validators
|
||||||
|
|||||||
@@ -77,6 +77,65 @@ def get_nested_value(
|
|||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
def get_field_extra_dict(
|
||||||
|
subfield_info: Union[FieldInfo, ComputedFieldInfo],
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""Extract json_schema_extra.
|
||||||
|
|
||||||
|
Extract regardless of whether it is defined directly
|
||||||
|
on the field (Pydantic v2) or inherited from v1 compatibility wrappers.
|
||||||
|
Always returns a dictionary.
|
||||||
|
"""
|
||||||
|
# Pydantic v2 location
|
||||||
|
extra = getattr(subfield_info, "json_schema_extra", None)
|
||||||
|
if isinstance(extra, dict):
|
||||||
|
return extra
|
||||||
|
|
||||||
|
# Pydantic v1 compatibility fallbacks
|
||||||
|
fi = getattr(subfield_info, "field_info", None)
|
||||||
|
if fi is not None:
|
||||||
|
extra = getattr(fi, "json_schema_extra", None)
|
||||||
|
if isinstance(extra, dict):
|
||||||
|
return extra
|
||||||
|
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def get_description(
|
||||||
|
subfield_info: Union[FieldInfo, ComputedFieldInfo],
|
||||||
|
extra: Dict[str, Any],
|
||||||
|
) -> str:
|
||||||
|
"""Fetch description.
|
||||||
|
|
||||||
|
Priority:
|
||||||
|
1) json_schema_extra["description"]
|
||||||
|
2) field_info.description
|
||||||
|
3) empty string
|
||||||
|
"""
|
||||||
|
if "description" in extra:
|
||||||
|
return str(extra["description"])
|
||||||
|
|
||||||
|
desc = getattr(subfield_info, "description", None)
|
||||||
|
return str(desc) if desc is not None else ""
|
||||||
|
|
||||||
|
|
||||||
|
def get_deprecated(
|
||||||
|
subfield_info: Union[FieldInfo, ComputedFieldInfo],
|
||||||
|
extra: Dict[str, Any],
|
||||||
|
) -> Optional[Any]:
|
||||||
|
"""Fetch deprecated.
|
||||||
|
|
||||||
|
Priority:
|
||||||
|
1) json_schema_extra["deprecated"]
|
||||||
|
2) field_info.deprecated
|
||||||
|
3) None
|
||||||
|
"""
|
||||||
|
if "deprecated" in extra:
|
||||||
|
return extra["deprecated"]
|
||||||
|
|
||||||
|
return getattr(subfield_info, "deprecated", None)
|
||||||
|
|
||||||
|
|
||||||
def get_default_value(field_info: Union[FieldInfo, ComputedFieldInfo], regular_field: bool) -> Any:
|
def get_default_value(field_info: Union[FieldInfo, ComputedFieldInfo], regular_field: bool) -> Any:
|
||||||
"""Retrieve the default value of a field.
|
"""Retrieve the default value of a field.
|
||||||
|
|
||||||
@@ -163,6 +222,7 @@ def configuration(
|
|||||||
):
|
):
|
||||||
if found_basic:
|
if found_basic:
|
||||||
continue
|
continue
|
||||||
|
extra = get_field_extra_dict(subfield_info)
|
||||||
|
|
||||||
config: dict[str, Optional[Any]] = {}
|
config: dict[str, Optional[Any]] = {}
|
||||||
config["name"] = ".".join(values_prefix + parent_types)
|
config["name"] = ".".join(values_prefix + parent_types)
|
||||||
@@ -170,12 +230,8 @@ def configuration(
|
|||||||
get_nested_value(values, values_prefix + parent_types, "<unknown>")
|
get_nested_value(values, values_prefix + parent_types, "<unknown>")
|
||||||
)
|
)
|
||||||
config["default"] = json.dumps(get_default_value(subfield_info, regular_field))
|
config["default"] = json.dumps(get_default_value(subfield_info, regular_field))
|
||||||
config["description"] = (
|
config["description"] = get_description(subfield_info, extra)
|
||||||
subfield_info.description if subfield_info.description else ""
|
config["deprecated"] = get_deprecated(subfield_info, extra)
|
||||||
)
|
|
||||||
config["deprecated"] = (
|
|
||||||
subfield_info.deprecated if subfield_info.deprecated else None
|
|
||||||
)
|
|
||||||
if isinstance(subfield_info, ComputedFieldInfo):
|
if isinstance(subfield_info, ComputedFieldInfo):
|
||||||
config["read-only"] = "ro"
|
config["read-only"] = "ro"
|
||||||
type_description = str(subfield_info.return_type)
|
type_description = str(subfield_info.return_type)
|
||||||
|
|||||||
@@ -153,31 +153,42 @@ class ServerCommonSettings(SettingsBaseModel):
|
|||||||
|
|
||||||
host: Optional[str] = Field(
|
host: Optional[str] = Field(
|
||||||
default=get_default_host(),
|
default=get_default_host(),
|
||||||
description="EOS server IP address. Defaults to 127.0.0.1.",
|
json_schema_extra={
|
||||||
examples=["127.0.0.1", "localhost"],
|
"description": "EOS server IP address. Defaults to 127.0.0.1.",
|
||||||
|
"examples": ["127.0.0.1", "localhost"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
port: Optional[int] = Field(
|
port: Optional[int] = Field(
|
||||||
default=8503,
|
default=8503,
|
||||||
description="EOS server IP port number. Defaults to 8503.",
|
json_schema_extra={
|
||||||
examples=[
|
"description": "EOS server IP port number. Defaults to 8503.",
|
||||||
|
"examples": [
|
||||||
8503,
|
8503,
|
||||||
],
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
verbose: Optional[bool] = Field(
|
||||||
|
default=False, json_schema_extra={"description": "Enable debug output"}
|
||||||
)
|
)
|
||||||
verbose: Optional[bool] = Field(default=False, description="Enable debug output")
|
|
||||||
startup_eosdash: Optional[bool] = Field(
|
startup_eosdash: Optional[bool] = Field(
|
||||||
default=True, description="EOS server to start EOSdash server. Defaults to True."
|
default=True,
|
||||||
|
json_schema_extra={"description": "EOS server to start EOSdash server. Defaults to True."},
|
||||||
)
|
)
|
||||||
eosdash_host: Optional[str] = Field(
|
eosdash_host: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="EOSdash server IP address. Defaults to EOS server IP address.",
|
json_schema_extra={
|
||||||
examples=["127.0.0.1", "localhost"],
|
"description": "EOSdash server IP address. Defaults to EOS server IP address.",
|
||||||
|
"examples": ["127.0.0.1", "localhost"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
eosdash_port: Optional[int] = Field(
|
eosdash_port: Optional[int] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="EOSdash server IP port number. Defaults to EOS server IP port number + 1.",
|
json_schema_extra={
|
||||||
examples=[
|
"description": "EOSdash server IP port number. Defaults to EOS server IP port number + 1.",
|
||||||
|
"examples": [
|
||||||
8504,
|
8504,
|
||||||
],
|
],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@field_validator("host", "eosdash_host", mode="before")
|
@field_validator("host", "eosdash_host", mode="before")
|
||||||
|
|||||||
@@ -835,31 +835,42 @@ class TimeWindow(BaseModel):
|
|||||||
Supports day names in multiple languages via locale-aware parsing.
|
Supports day names in multiple languages via locale-aware parsing.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
start_time: Time = Field(..., description="Start time of the time window (time of day).")
|
start_time: Time = Field(
|
||||||
|
..., json_schema_extra={"description": "Start time of the time window (time of day)."}
|
||||||
|
)
|
||||||
duration: Duration = Field(
|
duration: Duration = Field(
|
||||||
..., description="Duration of the time window starting from `start_time`."
|
...,
|
||||||
|
json_schema_extra={
|
||||||
|
"description": "Duration of the time window starting from `start_time`."
|
||||||
|
},
|
||||||
)
|
)
|
||||||
day_of_week: Optional[Union[int, str]] = Field(
|
day_of_week: Optional[Union[int, str]] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description=(
|
json_schema_extra={
|
||||||
|
"description": (
|
||||||
"Optional day of the week restriction. "
|
"Optional day of the week restriction. "
|
||||||
"Can be specified as integer (0=Monday to 6=Sunday) or localized weekday name. "
|
"Can be specified as integer (0=Monday to 6=Sunday) or localized weekday name. "
|
||||||
"If None, applies every day unless `date` is set."
|
"If None, applies every day unless `date` is set."
|
||||||
),
|
)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
date: Optional[Date] = Field(
|
date: Optional[Date] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description=(
|
json_schema_extra={
|
||||||
|
"description": (
|
||||||
"Optional specific calendar date for the time window. Overrides `day_of_week` if set."
|
"Optional specific calendar date for the time window. Overrides `day_of_week` if set."
|
||||||
),
|
)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
locale: Optional[str] = Field(
|
locale: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description=(
|
json_schema_extra={
|
||||||
|
"description": (
|
||||||
"Locale used to parse weekday names in `day_of_week` when given as string. "
|
"Locale used to parse weekday names in `day_of_week` when given as string. "
|
||||||
"If not set, Pendulum's default locale is used. "
|
"If not set, Pendulum's default locale is used. "
|
||||||
"Examples: 'en', 'de', 'fr', etc."
|
"Examples: 'en', 'de', 'fr', etc."
|
||||||
),
|
)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@field_validator("duration", mode="before")
|
@field_validator("duration", mode="before")
|
||||||
@@ -1160,7 +1171,8 @@ class TimeWindowSequence(BaseModel):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
windows: Optional[list[TimeWindow]] = Field(
|
windows: Optional[list[TimeWindow]] = Field(
|
||||||
default_factory=list, description="List of TimeWindow objects that make up this sequence."
|
default_factory=list,
|
||||||
|
json_schema_extra={"description": "List of TimeWindow objects that make up this sequence."},
|
||||||
)
|
)
|
||||||
|
|
||||||
@field_validator("windows")
|
@field_validator("windows")
|
||||||
|
|||||||
@@ -17,10 +17,40 @@ from akkudoktoreos.utils.datetimeutil import DateTime, compare_datetimes, to_dat
|
|||||||
|
|
||||||
|
|
||||||
class PydanticTestModel(PydanticBaseModel):
|
class PydanticTestModel(PydanticBaseModel):
|
||||||
|
"""Minimal test model for exercising PydanticBaseModel helpers."""
|
||||||
|
|
||||||
datetime_field: DateTime = Field(
|
datetime_field: DateTime = Field(
|
||||||
..., description="A datetime field with pendulum support."
|
...,
|
||||||
|
description="A datetime field with pendulum support.",
|
||||||
|
json_schema_extra={"description": "A datetime field with pendulum support."},
|
||||||
|
)
|
||||||
|
|
||||||
|
optional_field: Optional[str] = Field(
|
||||||
|
default=None,
|
||||||
|
# optional field with no description
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# Additional fields to support metadata-based testing
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
described_field: str = Field(
|
||||||
|
default="x",
|
||||||
|
description="A described string",
|
||||||
|
json_schema_extra={"description": "A described string"},
|
||||||
|
)
|
||||||
|
|
||||||
|
deprecated_field: str = Field(
|
||||||
|
default="y",
|
||||||
|
description="A deprecated string field",
|
||||||
|
json_schema_extra={"deprecated": "Use new_field instead"},
|
||||||
|
)
|
||||||
|
|
||||||
|
example_field: str = Field(
|
||||||
|
default="z",
|
||||||
|
description="An example-backed string field",
|
||||||
|
json_schema_extra={"examples": ["a", "b", "c"]},
|
||||||
)
|
)
|
||||||
optional_field: Optional[str] = Field(default=None, description="An optional field.")
|
|
||||||
|
|
||||||
|
|
||||||
class Address(PydanticBaseModel):
|
class Address(PydanticBaseModel):
|
||||||
@@ -377,6 +407,36 @@ class TestPydanticBaseModel:
|
|||||||
restored_model = PydanticTestModel.from_json(json_data)
|
restored_model = PydanticTestModel.from_json(json_data)
|
||||||
assert restored_model.datetime_field == dt
|
assert restored_model.datetime_field == dt
|
||||||
|
|
||||||
|
def test_field_extra_dict(self):
|
||||||
|
field = PydanticTestModel.model_fields["described_field"]
|
||||||
|
extra = PydanticTestModel._field_extra_dict(field)
|
||||||
|
assert isinstance(extra, dict)
|
||||||
|
assert extra.get("description") == "A described string"
|
||||||
|
|
||||||
|
def test_field_description(self):
|
||||||
|
result = PydanticTestModel.field_description("described_field")
|
||||||
|
assert result == "A described string"
|
||||||
|
|
||||||
|
def test_field_description_missing(self):
|
||||||
|
result = PydanticTestModel.field_description("optional_field")
|
||||||
|
assert result is None
|
||||||
|
|
||||||
|
def test_field_deprecated(self):
|
||||||
|
result = PydanticTestModel.field_deprecated("deprecated_field")
|
||||||
|
assert result == "Use new_field instead"
|
||||||
|
|
||||||
|
def test_field_deprecated_missing(self):
|
||||||
|
result = PydanticTestModel.field_deprecated("described_field")
|
||||||
|
assert result is None
|
||||||
|
|
||||||
|
def test_field_examples(self):
|
||||||
|
result = PydanticTestModel.field_examples("example_field")
|
||||||
|
assert result == ["a", "b", "c"]
|
||||||
|
|
||||||
|
def test_field_examples_missing(self):
|
||||||
|
result = PydanticTestModel.field_examples("optional_field")
|
||||||
|
assert result is None
|
||||||
|
|
||||||
|
|
||||||
class TestPydanticDateTimeData:
|
class TestPydanticDateTimeData:
|
||||||
def test_valid_list_lengths(self):
|
def test_valid_list_lengths(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user