mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2025-11-21 04:46:31 +00:00
chore: improve doc generation and test (#762)
Some checks failed
docker-build / platform-excludes (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
Run Pytest on Pull Request / test (push) Has been cancelled
docker-build / build (push) Has been cancelled
docker-build / merge (push) Has been cancelled
Close stale pull requests/issues / Find Stale issues and PRs (push) Has been cancelled
Some checks failed
docker-build / platform-excludes (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
Run Pytest on Pull Request / test (push) Has been cancelled
docker-build / build (push) Has been cancelled
docker-build / merge (push) Has been cancelled
Close stale pull requests/issues / Find Stale issues and PRs (push) Has been cancelled
Improve documentation generation and add tests for documentation. Extend sphinx by todo directive. The configuration table is now split into several tables. The test is adapted accordingly. There is a new test that checks the docstrings to be compliant to the RST format as used by sphinx to create the documentation. We can not use Markdown in docstrings. The docstrings are adapted accordingly. An additional test checks that the documentation can be build with sphinx. This test takes very long is only enabled in full run (aka. ci) mode. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
This commit is contained in:
@@ -37,7 +37,8 @@ repos:
|
|||||||
additional_dependencies:
|
additional_dependencies:
|
||||||
- types-requests==2.32.4.20250913
|
- types-requests==2.32.4.20250913
|
||||||
- pandas-stubs==2.3.2.250926
|
- pandas-stubs==2.3.2.250926
|
||||||
- tokenize-rt==3.2.0
|
- tokenize-rt==6.2.0
|
||||||
|
- types-docutils==0.22.2.20251006
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
|
|
||||||
# --- Markdown linter ---
|
# --- Markdown linter ---
|
||||||
@@ -46,7 +47,6 @@ repos:
|
|||||||
hooks:
|
hooks:
|
||||||
- id: pymarkdown
|
- id: pymarkdown
|
||||||
files: ^docs/
|
files: ^docs/
|
||||||
exclude: ^docs/_generated
|
|
||||||
args:
|
args:
|
||||||
- --config=docs/pymarkdown.json
|
- --config=docs/pymarkdown.json
|
||||||
- scan
|
- scan
|
||||||
|
|||||||
7
Makefile
7
Makefile
@@ -71,12 +71,13 @@ gen-docs: pip-dev
|
|||||||
|
|
||||||
# Target to build HTML documentation
|
# Target to build HTML documentation
|
||||||
docs: pip-dev
|
docs: pip-dev
|
||||||
.venv/bin/sphinx-build -M html docs build/docs
|
.venv/bin/pytest --full-run tests/test_docsphinx.py
|
||||||
@echo "Documentation build to build/docs/html/."
|
@echo "Documentation build to build/docs/html/."
|
||||||
|
|
||||||
# Target to read the HTML documentation
|
# Target to read the HTML documentation
|
||||||
read-docs: docs
|
read-docs:
|
||||||
@echo "Read the documentation in your browser"
|
@echo "Read the documentation in your browser"
|
||||||
|
.venv/bin/pytest --full-run tests/test_docsphinx.py
|
||||||
.venv/bin/python -m webbrowser build/docs/html/index.html
|
.venv/bin/python -m webbrowser build/docs/html/index.html
|
||||||
|
|
||||||
# Clean Python bytecode
|
# Clean Python bytecode
|
||||||
@@ -163,7 +164,7 @@ docker-build:
|
|||||||
|
|
||||||
# Bump Akkudoktoreos version
|
# Bump Akkudoktoreos version
|
||||||
VERSION ?= 0.2.0+dev
|
VERSION ?= 0.2.0+dev
|
||||||
NEW_VERSION ?= $(VERSION)+dev
|
NEW_VERSION ?= $(subst +dev,,$(VERSION))+dev # be careful - default is always +dev
|
||||||
|
|
||||||
bump: pip-dev
|
bump: pip-dev
|
||||||
@echo "Bumping akkudoktoreos version from $(VERSION) to $(NEW_VERSION) (dry-run: $(EXTRA_ARGS))"
|
@echo "Bumping akkudoktoreos version from $(VERSION) to $(NEW_VERSION) (dry-run: $(EXTRA_ARGS))"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
28
docs/_generated/configcache.md
Normal file
28
docs/_generated/configcache.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
## Cache Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} cache
|
||||||
|
:widths: 10 20 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
|
| cleanup_interval | `EOS_CACHE__CLEANUP_INTERVAL` | `float` | `rw` | `300` | Intervall in seconds for EOS file cache cleanup. |
|
||||||
|
| subpath | `EOS_CACHE__SUBPATH` | `Optional[pathlib.Path]` | `rw` | `cache` | Sub-path for the EOS cache data directory. |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"cache": {
|
||||||
|
"subpath": "cache",
|
||||||
|
"cleanup_interval": 300.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
405
docs/_generated/configdevices.md
Normal file
405
docs/_generated/configdevices.md
Normal file
@@ -0,0 +1,405 @@
|
|||||||
|
## Base configuration for devices simulation settings
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} devices
|
||||||
|
:widths: 10 20 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
|
| batteries | `EOS_DEVICES__BATTERIES` | `Optional[list[akkudoktoreos.devices.devices.BatteriesCommonSettings]]` | `rw` | `None` | List of battery devices |
|
||||||
|
| electric_vehicles | `EOS_DEVICES__ELECTRIC_VEHICLES` | `Optional[list[akkudoktoreos.devices.devices.BatteriesCommonSettings]]` | `rw` | `None` | List of electric vehicle devices |
|
||||||
|
| home_appliances | `EOS_DEVICES__HOME_APPLIANCES` | `Optional[list[akkudoktoreos.devices.devices.HomeApplianceCommonSettings]]` | `rw` | `None` | List of home appliances |
|
||||||
|
| inverters | `EOS_DEVICES__INVERTERS` | `Optional[list[akkudoktoreos.devices.devices.InverterCommonSettings]]` | `rw` | `None` | List of inverters |
|
||||||
|
| max_batteries | `EOS_DEVICES__MAX_BATTERIES` | `Optional[int]` | `rw` | `None` | Maximum number of batteries that can be set |
|
||||||
|
| max_electric_vehicles | `EOS_DEVICES__MAX_ELECTRIC_VEHICLES` | `Optional[int]` | `rw` | `None` | Maximum number of electric vehicles that can be set |
|
||||||
|
| max_home_appliances | `EOS_DEVICES__MAX_HOME_APPLIANCES` | `Optional[int]` | `rw` | `None` | Maximum number of home_appliances that can be set |
|
||||||
|
| max_inverters | `EOS_DEVICES__MAX_INVERTERS` | `Optional[int]` | `rw` | `None` | Maximum number of inverters that can be set |
|
||||||
|
| measurement_keys | | `Optional[list[str]]` | `ro` | `N/A` | None |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"devices": {
|
||||||
|
"batteries": [
|
||||||
|
{
|
||||||
|
"device_id": "battery1",
|
||||||
|
"capacity_wh": 8000,
|
||||||
|
"charging_efficiency": 0.88,
|
||||||
|
"discharging_efficiency": 0.88,
|
||||||
|
"levelized_cost_of_storage_kwh": 0.0,
|
||||||
|
"max_charge_power_w": 5000,
|
||||||
|
"min_charge_power_w": 50,
|
||||||
|
"charge_rates": "[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]",
|
||||||
|
"min_soc_percentage": 0,
|
||||||
|
"max_soc_percentage": 100,
|
||||||
|
"measurement_key_soc_factor": "battery1-soc-factor",
|
||||||
|
"measurement_key_power_l1_w": "battery1-power-l1-w",
|
||||||
|
"measurement_key_power_l2_w": "battery1-power-l2-w",
|
||||||
|
"measurement_key_power_l3_w": "battery1-power-l3-w",
|
||||||
|
"measurement_key_power_3_phase_sym_w": "battery1-power-3-phase-sym-w",
|
||||||
|
"measurement_keys": [
|
||||||
|
"battery1-soc-factor",
|
||||||
|
"battery1-power-l1-w",
|
||||||
|
"battery1-power-l2-w",
|
||||||
|
"battery1-power-l3-w",
|
||||||
|
"battery1-power-3-phase-sym-w"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"max_batteries": 1,
|
||||||
|
"electric_vehicles": [
|
||||||
|
{
|
||||||
|
"device_id": "battery1",
|
||||||
|
"capacity_wh": 8000,
|
||||||
|
"charging_efficiency": 0.88,
|
||||||
|
"discharging_efficiency": 0.88,
|
||||||
|
"levelized_cost_of_storage_kwh": 0.0,
|
||||||
|
"max_charge_power_w": 5000,
|
||||||
|
"min_charge_power_w": 50,
|
||||||
|
"charge_rates": "[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]",
|
||||||
|
"min_soc_percentage": 0,
|
||||||
|
"max_soc_percentage": 100,
|
||||||
|
"measurement_key_soc_factor": "battery1-soc-factor",
|
||||||
|
"measurement_key_power_l1_w": "battery1-power-l1-w",
|
||||||
|
"measurement_key_power_l2_w": "battery1-power-l2-w",
|
||||||
|
"measurement_key_power_l3_w": "battery1-power-l3-w",
|
||||||
|
"measurement_key_power_3_phase_sym_w": "battery1-power-3-phase-sym-w",
|
||||||
|
"measurement_keys": [
|
||||||
|
"battery1-soc-factor",
|
||||||
|
"battery1-power-l1-w",
|
||||||
|
"battery1-power-l2-w",
|
||||||
|
"battery1-power-l3-w",
|
||||||
|
"battery1-power-3-phase-sym-w"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"max_electric_vehicles": 1,
|
||||||
|
"inverters": [],
|
||||||
|
"max_inverters": 1,
|
||||||
|
"home_appliances": [],
|
||||||
|
"max_home_appliances": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"devices": {
|
||||||
|
"batteries": [
|
||||||
|
{
|
||||||
|
"device_id": "battery1",
|
||||||
|
"capacity_wh": 8000,
|
||||||
|
"charging_efficiency": 0.88,
|
||||||
|
"discharging_efficiency": 0.88,
|
||||||
|
"levelized_cost_of_storage_kwh": 0.0,
|
||||||
|
"max_charge_power_w": 5000,
|
||||||
|
"min_charge_power_w": 50,
|
||||||
|
"charge_rates": "[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]",
|
||||||
|
"min_soc_percentage": 0,
|
||||||
|
"max_soc_percentage": 100,
|
||||||
|
"measurement_key_soc_factor": "battery1-soc-factor",
|
||||||
|
"measurement_key_power_l1_w": "battery1-power-l1-w",
|
||||||
|
"measurement_key_power_l2_w": "battery1-power-l2-w",
|
||||||
|
"measurement_key_power_l3_w": "battery1-power-l3-w",
|
||||||
|
"measurement_key_power_3_phase_sym_w": "battery1-power-3-phase-sym-w",
|
||||||
|
"measurement_keys": [
|
||||||
|
"battery1-soc-factor",
|
||||||
|
"battery1-power-l1-w",
|
||||||
|
"battery1-power-l2-w",
|
||||||
|
"battery1-power-l3-w",
|
||||||
|
"battery1-power-3-phase-sym-w"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"max_batteries": 1,
|
||||||
|
"electric_vehicles": [
|
||||||
|
{
|
||||||
|
"device_id": "battery1",
|
||||||
|
"capacity_wh": 8000,
|
||||||
|
"charging_efficiency": 0.88,
|
||||||
|
"discharging_efficiency": 0.88,
|
||||||
|
"levelized_cost_of_storage_kwh": 0.0,
|
||||||
|
"max_charge_power_w": 5000,
|
||||||
|
"min_charge_power_w": 50,
|
||||||
|
"charge_rates": "[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]",
|
||||||
|
"min_soc_percentage": 0,
|
||||||
|
"max_soc_percentage": 100,
|
||||||
|
"measurement_key_soc_factor": "battery1-soc-factor",
|
||||||
|
"measurement_key_power_l1_w": "battery1-power-l1-w",
|
||||||
|
"measurement_key_power_l2_w": "battery1-power-l2-w",
|
||||||
|
"measurement_key_power_l3_w": "battery1-power-l3-w",
|
||||||
|
"measurement_key_power_3_phase_sym_w": "battery1-power-3-phase-sym-w",
|
||||||
|
"measurement_keys": [
|
||||||
|
"battery1-soc-factor",
|
||||||
|
"battery1-power-l1-w",
|
||||||
|
"battery1-power-l2-w",
|
||||||
|
"battery1-power-l3-w",
|
||||||
|
"battery1-power-3-phase-sym-w"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"max_electric_vehicles": 1,
|
||||||
|
"inverters": [],
|
||||||
|
"max_inverters": 1,
|
||||||
|
"home_appliances": [],
|
||||||
|
"max_home_appliances": 1,
|
||||||
|
"measurement_keys": [
|
||||||
|
"battery1-soc-factor",
|
||||||
|
"battery1-power-l1-w",
|
||||||
|
"battery1-power-l2-w",
|
||||||
|
"battery1-power-l3-w",
|
||||||
|
"battery1-power-3-phase-sym-w",
|
||||||
|
"battery1-soc-factor",
|
||||||
|
"battery1-power-l1-w",
|
||||||
|
"battery1-power-l2-w",
|
||||||
|
"battery1-power-l3-w",
|
||||||
|
"battery1-power-3-phase-sym-w"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### Inverter devices base settings
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} devices::inverters::list
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| battery_id | `Optional[str]` | `rw` | `None` | ID of battery controlled by this inverter. |
|
||||||
|
| device_id | `str` | `rw` | `<unknown>` | ID of device |
|
||||||
|
| max_power_w | `Optional[float]` | `rw` | `None` | Maximum power [W]. |
|
||||||
|
| measurement_keys | `Optional[list[str]]` | `ro` | `N/A` | None |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"devices": {
|
||||||
|
"inverters": [
|
||||||
|
{
|
||||||
|
"device_id": "battery1",
|
||||||
|
"max_power_w": 10000.0,
|
||||||
|
"battery_id": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"devices": {
|
||||||
|
"inverters": [
|
||||||
|
{
|
||||||
|
"device_id": "battery1",
|
||||||
|
"max_power_w": 10000.0,
|
||||||
|
"battery_id": null,
|
||||||
|
"measurement_keys": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### Home Appliance devices base settings
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} devices::home_appliances::list
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| consumption_wh | `int` | `rw` | `required` | Energy consumption [Wh]. |
|
||||||
|
| device_id | `str` | `rw` | `<unknown>` | ID of device |
|
||||||
|
| duration_h | `int` | `rw` | `required` | Usage duration in hours [0 ... 24]. |
|
||||||
|
| measurement_keys | `Optional[list[str]]` | `ro` | `N/A` | None |
|
||||||
|
| time_windows | `Optional[akkudoktoreos.utils.datetimeutil.TimeWindowSequence]` | `rw` | `None` | Sequence of allowed time windows. Defaults to optimization general time window. |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"devices": {
|
||||||
|
"home_appliances": [
|
||||||
|
{
|
||||||
|
"device_id": "battery1",
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"devices": {
|
||||||
|
"home_appliances": [
|
||||||
|
{
|
||||||
|
"device_id": "battery1",
|
||||||
|
"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": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### Battery devices base settings
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} devices::batteries::list
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| capacity_wh | `int` | `rw` | `8000` | Capacity [Wh]. |
|
||||||
|
| 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. |
|
||||||
|
| charging_efficiency | `float` | `rw` | `0.88` | Charging efficiency [0.01 ... 1.00]. |
|
||||||
|
| device_id | `str` | `rw` | `<unknown>` | ID of device |
|
||||||
|
| discharging_efficiency | `float` | `rw` | `0.88` | Discharge efficiency [0.01 ... 1.00]. |
|
||||||
|
| levelized_cost_of_storage_kwh | `float` | `rw` | `0.0` | Levelized cost of storage (LCOS), the average lifetime cost of delivering one kWh [€/kWh]. |
|
||||||
|
| max_charge_power_w | `Optional[float]` | `rw` | `5000` | Maximum charging power [W]. |
|
||||||
|
| max_soc_percentage | `int` | `rw` | `100` | Maximum state of charge (SOC) as percentage of capacity [%]. |
|
||||||
|
| measurement_key_power_3_phase_sym_w | `str` | `ro` | `N/A` | None |
|
||||||
|
| measurement_key_power_l1_w | `str` | `ro` | `N/A` | None |
|
||||||
|
| measurement_key_power_l2_w | `str` | `ro` | `N/A` | None |
|
||||||
|
| measurement_key_power_l3_w | `str` | `ro` | `N/A` | None |
|
||||||
|
| measurement_key_soc_factor | `str` | `ro` | `N/A` | None |
|
||||||
|
| measurement_keys | `Optional[list[str]]` | `ro` | `N/A` | None |
|
||||||
|
| min_charge_power_w | `Optional[float]` | `rw` | `50` | Minimum charging power [W]. |
|
||||||
|
| min_soc_percentage | `int` | `rw` | `0` | Minimum state of charge (SOC) as percentage of capacity [%]. This is the target SoC for charging |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"devices": {
|
||||||
|
"batteries": [
|
||||||
|
{
|
||||||
|
"device_id": "battery1",
|
||||||
|
"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.25 0.5 0.75 1. ]",
|
||||||
|
"min_soc_percentage": 10,
|
||||||
|
"max_soc_percentage": 100
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"devices": {
|
||||||
|
"batteries": [
|
||||||
|
{
|
||||||
|
"device_id": "battery1",
|
||||||
|
"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.25 0.5 0.75 1. ]",
|
||||||
|
"min_soc_percentage": 10,
|
||||||
|
"max_soc_percentage": 100,
|
||||||
|
"measurement_key_soc_factor": "battery1-soc-factor",
|
||||||
|
"measurement_key_power_l1_w": "battery1-power-l1-w",
|
||||||
|
"measurement_key_power_l2_w": "battery1-power-l2-w",
|
||||||
|
"measurement_key_power_l3_w": "battery1-power-l3-w",
|
||||||
|
"measurement_key_power_3_phase_sym_w": "battery1-power-3-phase-sym-w",
|
||||||
|
"measurement_keys": [
|
||||||
|
"battery1-soc-factor",
|
||||||
|
"battery1-power-l1-w",
|
||||||
|
"battery1-power-l2-w",
|
||||||
|
"battery1-power-l3-w",
|
||||||
|
"battery1-power-3-phase-sym-w"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
96
docs/_generated/configelecprice.md
Normal file
96
docs/_generated/configelecprice.md
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
## Electricity Price Prediction Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} elecprice
|
||||||
|
:widths: 10 20 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
|
| charges_kwh | `EOS_ELECPRICE__CHARGES_KWH` | `Optional[float]` | `rw` | `None` | Electricity price charges [€/kWh]. Will be added to variable market price. |
|
||||||
|
| provider | `EOS_ELECPRICE__PROVIDER` | `Optional[str]` | `rw` | `None` | Electricity price provider id of provider to be used. |
|
||||||
|
| provider_settings | `EOS_ELECPRICE__PROVIDER_SETTINGS` | `ElecPriceCommonProviderSettings` | `rw` | `required` | Provider settings |
|
||||||
|
| vat_rate | `EOS_ELECPRICE__VAT_RATE` | `Optional[float]` | `rw` | `1.19` | VAT rate factor applied to electricity price when charges are used. |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"elecprice": {
|
||||||
|
"provider": "ElecPriceAkkudoktor",
|
||||||
|
"charges_kwh": 0.21,
|
||||||
|
"vat_rate": 1.19,
|
||||||
|
"provider_settings": {
|
||||||
|
"ElecPriceImport": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### Common settings for elecprice data import from file or JSON String
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} elecprice::provider_settings::ElecPriceImport
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| import_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | Path to the file to import elecprice data from. |
|
||||||
|
| import_json | `Optional[str]` | `rw` | `None` | JSON string, dictionary of electricity price forecast value lists. |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"elecprice": {
|
||||||
|
"provider_settings": {
|
||||||
|
"ElecPriceImport": {
|
||||||
|
"import_file_path": null,
|
||||||
|
"import_json": "{\"elecprice_marketprice_wh\": [0.0003384, 0.0003318, 0.0003284]}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### Electricity Price Prediction Provider Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} elecprice::provider_settings
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| ElecPriceImport | `Optional[akkudoktoreos.prediction.elecpriceimport.ElecPriceImportCommonSettings]` | `rw` | `None` | ElecPriceImport settings |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"elecprice": {
|
||||||
|
"provider_settings": {
|
||||||
|
"ElecPriceImport": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
30
docs/_generated/configems.md
Normal file
30
docs/_generated/configems.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
## Energy Management Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} ems
|
||||||
|
:widths: 10 20 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
|
| interval | `EOS_EMS__INTERVAL` | `Optional[float]` | `rw` | `None` | Intervall in seconds between EOS energy management runs. |
|
||||||
|
| mode | `EOS_EMS__MODE` | `Optional[akkudoktoreos.core.emsettings.EnergyManagementMode]` | `rw` | `None` | Energy management mode [OPTIMIZATION | PREDICTION]. |
|
||||||
|
| startup_delay | `EOS_EMS__STARTUP_DELAY` | `float` | `rw` | `5` | Startup delay in seconds for EOS energy management runs. |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ems": {
|
||||||
|
"startup_delay": 5.0,
|
||||||
|
"interval": 300.0,
|
||||||
|
"mode": "OPTIMIZATION"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
211
docs/_generated/configexample.md
Normal file
211
docs/_generated/configexample.md
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
## Full example Config
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"cache": {
|
||||||
|
"subpath": "cache",
|
||||||
|
"cleanup_interval": 300.0
|
||||||
|
},
|
||||||
|
"devices": {
|
||||||
|
"batteries": [
|
||||||
|
{
|
||||||
|
"device_id": "battery1",
|
||||||
|
"capacity_wh": 8000,
|
||||||
|
"charging_efficiency": 0.88,
|
||||||
|
"discharging_efficiency": 0.88,
|
||||||
|
"levelized_cost_of_storage_kwh": 0.0,
|
||||||
|
"max_charge_power_w": 5000,
|
||||||
|
"min_charge_power_w": 50,
|
||||||
|
"charge_rates": "[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]",
|
||||||
|
"min_soc_percentage": 0,
|
||||||
|
"max_soc_percentage": 100,
|
||||||
|
"measurement_key_soc_factor": "battery1-soc-factor",
|
||||||
|
"measurement_key_power_l1_w": "battery1-power-l1-w",
|
||||||
|
"measurement_key_power_l2_w": "battery1-power-l2-w",
|
||||||
|
"measurement_key_power_l3_w": "battery1-power-l3-w",
|
||||||
|
"measurement_key_power_3_phase_sym_w": "battery1-power-3-phase-sym-w",
|
||||||
|
"measurement_keys": [
|
||||||
|
"battery1-soc-factor",
|
||||||
|
"battery1-power-l1-w",
|
||||||
|
"battery1-power-l2-w",
|
||||||
|
"battery1-power-l3-w",
|
||||||
|
"battery1-power-3-phase-sym-w"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"max_batteries": 1,
|
||||||
|
"electric_vehicles": [
|
||||||
|
{
|
||||||
|
"device_id": "battery1",
|
||||||
|
"capacity_wh": 8000,
|
||||||
|
"charging_efficiency": 0.88,
|
||||||
|
"discharging_efficiency": 0.88,
|
||||||
|
"levelized_cost_of_storage_kwh": 0.0,
|
||||||
|
"max_charge_power_w": 5000,
|
||||||
|
"min_charge_power_w": 50,
|
||||||
|
"charge_rates": "[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]",
|
||||||
|
"min_soc_percentage": 0,
|
||||||
|
"max_soc_percentage": 100,
|
||||||
|
"measurement_key_soc_factor": "battery1-soc-factor",
|
||||||
|
"measurement_key_power_l1_w": "battery1-power-l1-w",
|
||||||
|
"measurement_key_power_l2_w": "battery1-power-l2-w",
|
||||||
|
"measurement_key_power_l3_w": "battery1-power-l3-w",
|
||||||
|
"measurement_key_power_3_phase_sym_w": "battery1-power-3-phase-sym-w",
|
||||||
|
"measurement_keys": [
|
||||||
|
"battery1-soc-factor",
|
||||||
|
"battery1-power-l1-w",
|
||||||
|
"battery1-power-l2-w",
|
||||||
|
"battery1-power-l3-w",
|
||||||
|
"battery1-power-3-phase-sym-w"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"max_electric_vehicles": 1,
|
||||||
|
"inverters": [],
|
||||||
|
"max_inverters": 1,
|
||||||
|
"home_appliances": [],
|
||||||
|
"max_home_appliances": 1
|
||||||
|
},
|
||||||
|
"elecprice": {
|
||||||
|
"provider": "ElecPriceAkkudoktor",
|
||||||
|
"charges_kwh": 0.21,
|
||||||
|
"vat_rate": 1.19,
|
||||||
|
"provider_settings": {
|
||||||
|
"ElecPriceImport": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ems": {
|
||||||
|
"startup_delay": 5.0,
|
||||||
|
"interval": 300.0,
|
||||||
|
"mode": "OPTIMIZATION"
|
||||||
|
},
|
||||||
|
"feedintariff": {
|
||||||
|
"provider": "FeedInTariffFixed",
|
||||||
|
"provider_settings": {
|
||||||
|
"FeedInTariffFixed": null,
|
||||||
|
"FeedInTariffImport": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"version": "0.2.0+dev",
|
||||||
|
"data_folder_path": null,
|
||||||
|
"data_output_subpath": "output",
|
||||||
|
"latitude": 52.52,
|
||||||
|
"longitude": 13.405
|
||||||
|
},
|
||||||
|
"load": {
|
||||||
|
"provider": "LoadAkkudoktor",
|
||||||
|
"provider_settings": {
|
||||||
|
"LoadAkkudoktor": null,
|
||||||
|
"LoadVrm": null,
|
||||||
|
"LoadImport": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"logging": {
|
||||||
|
"console_level": "TRACE",
|
||||||
|
"file_level": "TRACE"
|
||||||
|
},
|
||||||
|
"measurement": {
|
||||||
|
"load_emr_keys": [
|
||||||
|
"load0_emr"
|
||||||
|
],
|
||||||
|
"grid_export_emr_keys": [
|
||||||
|
"grid_export_emr"
|
||||||
|
],
|
||||||
|
"grid_import_emr_keys": [
|
||||||
|
"grid_import_emr"
|
||||||
|
],
|
||||||
|
"pv_production_emr_keys": [
|
||||||
|
"pv1_emr"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"optimization": {
|
||||||
|
"horizon_hours": 24,
|
||||||
|
"interval": 3600,
|
||||||
|
"algorithm": "GENETIC",
|
||||||
|
"genetic": {
|
||||||
|
"individuals": 400,
|
||||||
|
"generations": 400,
|
||||||
|
"seed": null,
|
||||||
|
"penalties": {
|
||||||
|
"ev_soc_miss": 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"prediction": {
|
||||||
|
"hours": 48,
|
||||||
|
"historic_hours": 48
|
||||||
|
},
|
||||||
|
"pvforecast": {
|
||||||
|
"provider": "PVForecastAkkudoktor",
|
||||||
|
"provider_settings": {
|
||||||
|
"PVForecastImport": null,
|
||||||
|
"PVForecastVrm": null
|
||||||
|
},
|
||||||
|
"planes": [
|
||||||
|
{
|
||||||
|
"surface_tilt": 10.0,
|
||||||
|
"surface_azimuth": 180.0,
|
||||||
|
"userhorizon": [
|
||||||
|
10.0,
|
||||||
|
20.0,
|
||||||
|
30.0
|
||||||
|
],
|
||||||
|
"peakpower": 5.0,
|
||||||
|
"pvtechchoice": "crystSi",
|
||||||
|
"mountingplace": "free",
|
||||||
|
"loss": 14.0,
|
||||||
|
"trackingtype": 0,
|
||||||
|
"optimal_surface_tilt": false,
|
||||||
|
"optimalangles": false,
|
||||||
|
"albedo": null,
|
||||||
|
"module_model": null,
|
||||||
|
"inverter_model": null,
|
||||||
|
"inverter_paco": 6000,
|
||||||
|
"modules_per_string": 20,
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"max_planes": 1
|
||||||
|
},
|
||||||
|
"server": {
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": 8503,
|
||||||
|
"verbose": false,
|
||||||
|
"startup_eosdash": true,
|
||||||
|
"eosdash_host": "127.0.0.1",
|
||||||
|
"eosdash_port": 8504
|
||||||
|
},
|
||||||
|
"utils": {},
|
||||||
|
"weather": {
|
||||||
|
"provider": "WeatherImport",
|
||||||
|
"provider_settings": {
|
||||||
|
"WeatherImport": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
126
docs/_generated/configfeedintariff.md
Normal file
126
docs/_generated/configfeedintariff.md
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
## Feed In Tariff Prediction Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} feedintariff
|
||||||
|
:widths: 10 20 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| 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_settings | `EOS_FEEDINTARIFF__PROVIDER_SETTINGS` | `FeedInTariffCommonProviderSettings` | `rw` | `required` | Provider settings |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"feedintariff": {
|
||||||
|
"provider": "FeedInTariffFixed",
|
||||||
|
"provider_settings": {
|
||||||
|
"FeedInTariffFixed": null,
|
||||||
|
"FeedInTariffImport": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### Common settings for feed in tariff data import from file or JSON string
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} feedintariff::provider_settings::FeedInTariffImport
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| import_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | Path to the file to import feed in tariff data from. |
|
||||||
|
| import_json | `Optional[str]` | `rw` | `None` | JSON string, dictionary of feed in tariff forecast value lists. |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"feedintariff": {
|
||||||
|
"provider_settings": {
|
||||||
|
"FeedInTariffImport": {
|
||||||
|
"import_file_path": null,
|
||||||
|
"import_json": "{\"fead_in_tariff_wh\": [0.000078, 0.000078, 0.000023]}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### Common settings for elecprice fixed price
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} feedintariff::provider_settings::FeedInTariffFixed
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| feed_in_tariff_kwh | `Optional[float]` | `rw` | `None` | Electricity price feed in tariff [€/kWH]. |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"feedintariff": {
|
||||||
|
"provider_settings": {
|
||||||
|
"FeedInTariffFixed": {
|
||||||
|
"feed_in_tariff_kwh": 0.078
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### Feed In Tariff Prediction Provider Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} feedintariff::provider_settings
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| FeedInTariffFixed | `Optional[akkudoktoreos.prediction.feedintarifffixed.FeedInTariffFixedCommonSettings]` | `rw` | `None` | FeedInTariffFixed settings |
|
||||||
|
| FeedInTariffImport | `Optional[akkudoktoreos.prediction.feedintariffimport.FeedInTariffImportCommonSettings]` | `rw` | `None` | FeedInTariffImport settings |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"feedintariff": {
|
||||||
|
"provider_settings": {
|
||||||
|
"FeedInTariffFixed": null,
|
||||||
|
"FeedInTariffImport": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
73
docs/_generated/configgeneral.md
Normal file
73
docs/_generated/configgeneral.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
## Settings for common configuration
|
||||||
|
|
||||||
|
General configuration to set directories of cache and output files and system location (latitude
|
||||||
|
and longitude).
|
||||||
|
Validators ensure each parameter is within a specified range. A computed property, `timezone`,
|
||||||
|
determines the time zone based on latitude and longitude.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
latitude (Optional[float]): Latitude in degrees, must be between -90 and 90.
|
||||||
|
longitude (Optional[float]): Longitude in degrees, must be between -180 and 180.
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
timezone (Optional[str]): Computed time zone string based on the specified latitude
|
||||||
|
and longitude.
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} general
|
||||||
|
:widths: 10 20 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
|
| config_file_path | | `Optional[pathlib.Path]` | `ro` | `N/A` | None |
|
||||||
|
| config_folder_path | | `Optional[pathlib.Path]` | `ro` | `N/A` | None |
|
||||||
|
| data_folder_path | `EOS_GENERAL__DATA_FOLDER_PATH` | `Optional[pathlib.Path]` | `rw` | `None` | Path to EOS data directory. |
|
||||||
|
| data_output_path | | `Optional[pathlib.Path]` | `ro` | `N/A` | None |
|
||||||
|
| data_output_subpath | `EOS_GENERAL__DATA_OUTPUT_SUBPATH` | `Optional[pathlib.Path]` | `rw` | `output` | Sub-path for the EOS output data directory. |
|
||||||
|
| latitude | `EOS_GENERAL__LATITUDE` | `Optional[float]` | `rw` | `52.52` | Latitude in decimal degrees, between -90 and 90, north is positive (ISO 19115) (°) |
|
||||||
|
| longitude | `EOS_GENERAL__LONGITUDE` | `Optional[float]` | `rw` | `13.405` | Longitude in decimal degrees, within -180 to 180 (°) |
|
||||||
|
| timezone | | `Optional[str]` | `ro` | `N/A` | None |
|
||||||
|
| version | `EOS_GENERAL__VERSION` | `str` | `rw` | `0.2.0+dev` | Configuration file version. Used to check compatibility. |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"general": {
|
||||||
|
"version": "0.2.0+dev",
|
||||||
|
"data_folder_path": null,
|
||||||
|
"data_output_subpath": "output",
|
||||||
|
"latitude": 52.52,
|
||||||
|
"longitude": 13.405
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"general": {
|
||||||
|
"version": "0.2.0+dev",
|
||||||
|
"data_folder_path": null,
|
||||||
|
"data_output_subpath": "output",
|
||||||
|
"latitude": 52.52,
|
||||||
|
"longitude": 13.405,
|
||||||
|
"timezone": "Europe/Berlin",
|
||||||
|
"data_output_path": null,
|
||||||
|
"config_folder_path": "/home/user/.config/net.akkudoktoreos.net",
|
||||||
|
"config_file_path": "/home/user/.config/net.akkudoktoreos.net/EOS.config.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
162
docs/_generated/configload.md
Normal file
162
docs/_generated/configload.md
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
## Load Prediction Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} load
|
||||||
|
:widths: 10 20 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| 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_settings | `EOS_LOAD__PROVIDER_SETTINGS` | `LoadCommonProviderSettings` | `rw` | `required` | Provider settings |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"load": {
|
||||||
|
"provider": "LoadAkkudoktor",
|
||||||
|
"provider_settings": {
|
||||||
|
"LoadAkkudoktor": null,
|
||||||
|
"LoadVrm": null,
|
||||||
|
"LoadImport": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### Common settings for load data import from file or JSON string
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} load::provider_settings::LoadImport
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| import_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | Path to the file to import load data from. |
|
||||||
|
| import_json | `Optional[str]` | `rw` | `None` | JSON string, dictionary of load forecast value lists. |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"load": {
|
||||||
|
"provider_settings": {
|
||||||
|
"LoadImport": {
|
||||||
|
"import_file_path": null,
|
||||||
|
"import_json": "{\"load0_mean\": [676.71, 876.19, 527.13]}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### Common settings for VRM API
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} load::provider_settings::LoadVrm
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| load_vrm_idsite | `int` | `rw` | `12345` | VRM-Installation-ID |
|
||||||
|
| load_vrm_token | `str` | `rw` | `your-token` | Token for Connecting VRM API |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"load": {
|
||||||
|
"provider_settings": {
|
||||||
|
"LoadVrm": {
|
||||||
|
"load_vrm_token": "your-token",
|
||||||
|
"load_vrm_idsite": 12345
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### Common settings for load data import from file
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} load::provider_settings::LoadAkkudoktor
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| loadakkudoktor_year_energy_kwh | `Optional[float]` | `rw` | `None` | Yearly energy consumption (kWh). |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"load": {
|
||||||
|
"provider_settings": {
|
||||||
|
"LoadAkkudoktor": {
|
||||||
|
"loadakkudoktor_year_energy_kwh": 40421.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### Load Prediction Provider Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} load::provider_settings
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| LoadAkkudoktor | `Optional[akkudoktoreos.prediction.loadakkudoktor.LoadAkkudoktorCommonSettings]` | `rw` | `None` | LoadAkkudoktor settings |
|
||||||
|
| LoadImport | `Optional[akkudoktoreos.prediction.loadimport.LoadImportCommonSettings]` | `rw` | `None` | LoadImport settings |
|
||||||
|
| LoadVrm | `Optional[akkudoktoreos.prediction.loadvrm.LoadVrmCommonSettings]` | `rw` | `None` | LoadVrm settings |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"load": {
|
||||||
|
"provider_settings": {
|
||||||
|
"LoadAkkudoktor": null,
|
||||||
|
"LoadVrm": null,
|
||||||
|
"LoadImport": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
45
docs/_generated/configlogging.md
Normal file
45
docs/_generated/configlogging.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
## Logging Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} logging
|
||||||
|
:widths: 10 20 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
|
| console_level | `EOS_LOGGING__CONSOLE_LEVEL` | `Optional[str]` | `rw` | `None` | Logging level when logging to console. |
|
||||||
|
| file_level | `EOS_LOGGING__FILE_LEVEL` | `Optional[str]` | `rw` | `None` | Logging level when logging to file. |
|
||||||
|
| file_path | | `Optional[pathlib.Path]` | `ro` | `N/A` | None |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"logging": {
|
||||||
|
"console_level": "TRACE",
|
||||||
|
"file_level": "TRACE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"logging": {
|
||||||
|
"console_level": "TRACE",
|
||||||
|
"file_level": "TRACE",
|
||||||
|
"file_path": "/home/user/.local/share/net.akkudoktor.eos/output/eos.log"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
72
docs/_generated/configmeasurement.md
Normal file
72
docs/_generated/configmeasurement.md
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
## Measurement Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} measurement
|
||||||
|
:widths: 10 20 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
|
| 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_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]. |
|
||||||
|
| keys | | `list[str]` | `ro` | `N/A` | None |
|
||||||
|
| 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]. |
|
||||||
|
| 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]. |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"measurement": {
|
||||||
|
"load_emr_keys": [
|
||||||
|
"load0_emr"
|
||||||
|
],
|
||||||
|
"grid_export_emr_keys": [
|
||||||
|
"grid_export_emr"
|
||||||
|
],
|
||||||
|
"grid_import_emr_keys": [
|
||||||
|
"grid_import_emr"
|
||||||
|
],
|
||||||
|
"pv_production_emr_keys": [
|
||||||
|
"pv1_emr"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"measurement": {
|
||||||
|
"load_emr_keys": [
|
||||||
|
"load0_emr"
|
||||||
|
],
|
||||||
|
"grid_export_emr_keys": [
|
||||||
|
"grid_export_emr"
|
||||||
|
],
|
||||||
|
"grid_import_emr_keys": [
|
||||||
|
"grid_import_emr"
|
||||||
|
],
|
||||||
|
"pv_production_emr_keys": [
|
||||||
|
"pv1_emr"
|
||||||
|
],
|
||||||
|
"keys": [
|
||||||
|
"grid_export_emr",
|
||||||
|
"grid_import_emr",
|
||||||
|
"load0_emr",
|
||||||
|
"pv1_emr"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
76
docs/_generated/configoptimization.md
Normal file
76
docs/_generated/configoptimization.md
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
## General Optimization Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} optimization
|
||||||
|
:widths: 10 20 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
|
| algorithm | `EOS_OPTIMIZATION__ALGORITHM` | `Optional[str]` | `rw` | `GENETIC` | The optimization algorithm. |
|
||||||
|
| genetic | `EOS_OPTIMIZATION__GENETIC` | `Optional[akkudoktoreos.optimization.optimization.GeneticCommonSettings]` | `rw` | `None` | Genetic optimization algorithm configuration. |
|
||||||
|
| 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. |
|
||||||
|
| interval | `EOS_OPTIMIZATION__INTERVAL` | `Optional[int]` | `rw` | `3600` | The optimization interval [sec]. |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"optimization": {
|
||||||
|
"horizon_hours": 24,
|
||||||
|
"interval": 3600,
|
||||||
|
"algorithm": "GENETIC",
|
||||||
|
"genetic": {
|
||||||
|
"individuals": 400,
|
||||||
|
"generations": 400,
|
||||||
|
"seed": null,
|
||||||
|
"penalties": {
|
||||||
|
"ev_soc_miss": 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### General Genetic Optimization Algorithm Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} optimization::genetic
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| generations | `Optional[int]` | `rw` | `400` | Number of generations to evaluate the optimal solution [>= 10]. Defaults to 400. |
|
||||||
|
| individuals | `Optional[int]` | `rw` | `300` | Number of individuals (solutions) to generate for the (initial) generation [>= 10]. Defaults to 300. |
|
||||||
|
| 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. |
|
||||||
|
| seed | `Optional[int]` | `rw` | `None` | Fixed seed for genetic algorithm. Defaults to 'None' which means random seed. |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"optimization": {
|
||||||
|
"genetic": {
|
||||||
|
"individuals": 300,
|
||||||
|
"generations": 400,
|
||||||
|
"seed": null,
|
||||||
|
"penalties": {
|
||||||
|
"ev_soc_miss": 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
42
docs/_generated/configprediction.md
Normal file
42
docs/_generated/configprediction.md
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
## General Prediction Configuration
|
||||||
|
|
||||||
|
This class provides configuration for prediction settings, allowing users to specify
|
||||||
|
parameters such as the forecast duration (in hours).
|
||||||
|
Validators ensure each parameter is within a specified range.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
hours (Optional[int]): Number of hours into the future for predictions.
|
||||||
|
Must be non-negative.
|
||||||
|
historic_hours (Optional[int]): Number of hours into the past for historical data.
|
||||||
|
Must be non-negative.
|
||||||
|
|
||||||
|
Validators:
|
||||||
|
validate_hours (int): Ensures `hours` is a non-negative integer.
|
||||||
|
validate_historic_hours (int): Ensures `historic_hours` is a non-negative integer.
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} prediction
|
||||||
|
:widths: 10 20 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
|
| historic_hours | `EOS_PREDICTION__HISTORIC_HOURS` | `Optional[int]` | `rw` | `48` | Number of hours into the past for historical predictions data |
|
||||||
|
| hours | `EOS_PREDICTION__HOURS` | `Optional[int]` | `rw` | `48` | Number of hours into the future for predictions |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"prediction": {
|
||||||
|
"hours": 48,
|
||||||
|
"historic_hours": 48
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
340
docs/_generated/configpvforecast.md
Normal file
340
docs/_generated/configpvforecast.md
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
## PV Forecast Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} pvforecast
|
||||||
|
:widths: 10 20 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
|
| max_planes | `EOS_PVFORECAST__MAX_PLANES` | `Optional[int]` | `rw` | `0` | Maximum number of planes that can be set |
|
||||||
|
| planes | `EOS_PVFORECAST__PLANES` | `Optional[list[akkudoktoreos.prediction.pvforecast.PVForecastPlaneSetting]]` | `rw` | `None` | Plane configuration. |
|
||||||
|
| planes_azimuth | | `List[float]` | `ro` | `N/A` | None |
|
||||||
|
| planes_inverter_paco | | `Any` | `ro` | `N/A` | None |
|
||||||
|
| planes_peakpower | | `List[float]` | `ro` | `N/A` | None |
|
||||||
|
| planes_tilt | | `List[float]` | `ro` | `N/A` | None |
|
||||||
|
| planes_userhorizon | | `Any` | `ro` | `N/A` | None |
|
||||||
|
| provider | `EOS_PVFORECAST__PROVIDER` | `Optional[str]` | `rw` | `None` | PVForecast provider id of provider to be used. |
|
||||||
|
| provider_settings | `EOS_PVFORECAST__PROVIDER_SETTINGS` | `PVForecastCommonProviderSettings` | `rw` | `required` | Provider settings |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"pvforecast": {
|
||||||
|
"provider": "PVForecastAkkudoktor",
|
||||||
|
"provider_settings": {
|
||||||
|
"PVForecastImport": null,
|
||||||
|
"PVForecastVrm": null
|
||||||
|
},
|
||||||
|
"planes": [
|
||||||
|
{
|
||||||
|
"surface_tilt": 10.0,
|
||||||
|
"surface_azimuth": 180.0,
|
||||||
|
"userhorizon": [
|
||||||
|
10.0,
|
||||||
|
20.0,
|
||||||
|
30.0
|
||||||
|
],
|
||||||
|
"peakpower": 5.0,
|
||||||
|
"pvtechchoice": "crystSi",
|
||||||
|
"mountingplace": "free",
|
||||||
|
"loss": 14.0,
|
||||||
|
"trackingtype": 0,
|
||||||
|
"optimal_surface_tilt": false,
|
||||||
|
"optimalangles": false,
|
||||||
|
"albedo": null,
|
||||||
|
"module_model": null,
|
||||||
|
"inverter_model": null,
|
||||||
|
"inverter_paco": 6000,
|
||||||
|
"modules_per_string": 20,
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"max_planes": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"pvforecast": {
|
||||||
|
"provider": "PVForecastAkkudoktor",
|
||||||
|
"provider_settings": {
|
||||||
|
"PVForecastImport": null,
|
||||||
|
"PVForecastVrm": null
|
||||||
|
},
|
||||||
|
"planes": [
|
||||||
|
{
|
||||||
|
"surface_tilt": 10.0,
|
||||||
|
"surface_azimuth": 180.0,
|
||||||
|
"userhorizon": [
|
||||||
|
10.0,
|
||||||
|
20.0,
|
||||||
|
30.0
|
||||||
|
],
|
||||||
|
"peakpower": 5.0,
|
||||||
|
"pvtechchoice": "crystSi",
|
||||||
|
"mountingplace": "free",
|
||||||
|
"loss": 14.0,
|
||||||
|
"trackingtype": 0,
|
||||||
|
"optimal_surface_tilt": false,
|
||||||
|
"optimalangles": false,
|
||||||
|
"albedo": null,
|
||||||
|
"module_model": null,
|
||||||
|
"inverter_model": null,
|
||||||
|
"inverter_paco": 6000,
|
||||||
|
"modules_per_string": 20,
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"max_planes": 1,
|
||||||
|
"planes_peakpower": [
|
||||||
|
5.0,
|
||||||
|
3.5
|
||||||
|
],
|
||||||
|
"planes_azimuth": [
|
||||||
|
180.0,
|
||||||
|
90.0
|
||||||
|
],
|
||||||
|
"planes_tilt": [
|
||||||
|
10.0,
|
||||||
|
20.0
|
||||||
|
],
|
||||||
|
"planes_userhorizon": [
|
||||||
|
[
|
||||||
|
10.0,
|
||||||
|
20.0,
|
||||||
|
30.0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
5.0,
|
||||||
|
15.0,
|
||||||
|
25.0
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"planes_inverter_paco": [
|
||||||
|
6000.0,
|
||||||
|
4000.0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### Common settings for VRM API
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} pvforecast::provider_settings::PVForecastVrm
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| pvforecast_vrm_idsite | `int` | `rw` | `12345` | VRM-Installation-ID |
|
||||||
|
| pvforecast_vrm_token | `str` | `rw` | `your-token` | Token for Connecting VRM API |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"pvforecast": {
|
||||||
|
"provider_settings": {
|
||||||
|
"PVForecastVrm": {
|
||||||
|
"pvforecast_vrm_token": "your-token",
|
||||||
|
"pvforecast_vrm_idsite": 12345
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### Common settings for pvforecast data import from file or JSON string
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} pvforecast::provider_settings::PVForecastImport
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| import_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | Path to the file to import PV forecast data from. |
|
||||||
|
| import_json | `Optional[str]` | `rw` | `None` | JSON string, dictionary of PV forecast value lists. |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"pvforecast": {
|
||||||
|
"provider_settings": {
|
||||||
|
"PVForecastImport": {
|
||||||
|
"import_file_path": null,
|
||||||
|
"import_json": "{\"pvforecast_ac_power\": [0, 8.05, 352.91]}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### PV Forecast Provider Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} pvforecast::provider_settings
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| PVForecastImport | `Optional[akkudoktoreos.prediction.pvforecastimport.PVForecastImportCommonSettings]` | `rw` | `None` | PVForecastImport settings |
|
||||||
|
| PVForecastVrm | `Optional[akkudoktoreos.prediction.pvforecastvrm.PVForecastVrmCommonSettings]` | `rw` | `None` | PVForecastVrm settings |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"pvforecast": {
|
||||||
|
"provider_settings": {
|
||||||
|
"PVForecastImport": null,
|
||||||
|
"PVForecastVrm": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### PV Forecast Plane Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} pvforecast::planes::list
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| albedo | `Optional[float]` | `rw` | `None` | Proportion of the light hitting the ground that it reflects back. |
|
||||||
|
| inverter_model | `Optional[str]` | `rw` | `None` | Model of the inverter of this plane. |
|
||||||
|
| inverter_paco | `Optional[int]` | `rw` | `None` | AC power rating of the inverter [W]. |
|
||||||
|
| loss | `Optional[float]` | `rw` | `14.0` | Sum of PV system losses in percent |
|
||||||
|
| module_model | `Optional[str]` | `rw` | `None` | Model of the PV modules of this plane. |
|
||||||
|
| modules_per_string | `Optional[int]` | `rw` | `None` | Number of the PV modules of the strings of this plane. |
|
||||||
|
| mountingplace | `Optional[str]` | `rw` | `free` | Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated. |
|
||||||
|
| optimal_surface_tilt | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt angle. Ignored for two-axis tracking. |
|
||||||
|
| optimalangles | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking. |
|
||||||
|
| peakpower | `Optional[float]` | `rw` | `None` | Nominal power of PV system in kW. |
|
||||||
|
| pvtechchoice | `Optional[str]` | `rw` | `crystSi` | PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'. |
|
||||||
|
| strings_per_inverter | `Optional[int]` | `rw` | `None` | Number of the strings of the inverter of this plane. |
|
||||||
|
| 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_tilt | `Optional[float]` | `rw` | `30.0` | Tilt angle from horizontal plane. Ignored for two-axis tracking. |
|
||||||
|
| 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. |
|
||||||
|
| userhorizon | `Optional[List[float]]` | `rw` | `None` | Elevation of horizon in degrees, at equally spaced azimuth clockwise from north. |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"pvforecast": {
|
||||||
|
"planes": [
|
||||||
|
{
|
||||||
|
"surface_tilt": 10.0,
|
||||||
|
"surface_azimuth": 180.0,
|
||||||
|
"userhorizon": [
|
||||||
|
10.0,
|
||||||
|
20.0,
|
||||||
|
30.0
|
||||||
|
],
|
||||||
|
"peakpower": 5.0,
|
||||||
|
"pvtechchoice": "crystSi",
|
||||||
|
"mountingplace": "free",
|
||||||
|
"loss": 14.0,
|
||||||
|
"trackingtype": 0,
|
||||||
|
"optimal_surface_tilt": false,
|
||||||
|
"optimalangles": false,
|
||||||
|
"albedo": null,
|
||||||
|
"module_model": null,
|
||||||
|
"inverter_model": null,
|
||||||
|
"inverter_paco": 6000,
|
||||||
|
"modules_per_string": 20,
|
||||||
|
"strings_per_inverter": 2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
36
docs/_generated/configserver.md
Normal file
36
docs/_generated/configserver.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
## Server Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} server
|
||||||
|
:widths: 10 20 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
|
| eosdash_host | `EOS_SERVER__EOSDASH_HOST` | `Optional[str]` | `rw` | `None` | EOSdash server IP address. Defaults to EOS server IP address. |
|
||||||
|
| eosdash_port | `EOS_SERVER__EOSDASH_PORT` | `Optional[int]` | `rw` | `None` | EOSdash server IP port number. Defaults to EOS server IP port number + 1. |
|
||||||
|
| host | `EOS_SERVER__HOST` | `Optional[str]` | `rw` | `127.0.0.1` | EOS server IP address. Defaults to 127.0.0.1. |
|
||||||
|
| port | `EOS_SERVER__PORT` | `Optional[int]` | `rw` | `8503` | EOS server IP port number. Defaults to 8503. |
|
||||||
|
| startup_eosdash | `EOS_SERVER__STARTUP_EOSDASH` | `Optional[bool]` | `rw` | `True` | EOS server to start EOSdash server. Defaults to True. |
|
||||||
|
| verbose | `EOS_SERVER__VERBOSE` | `Optional[bool]` | `rw` | `False` | Enable debug output |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"server": {
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": 8503,
|
||||||
|
"verbose": false,
|
||||||
|
"startup_eosdash": true,
|
||||||
|
"eosdash_host": "127.0.0.1",
|
||||||
|
"eosdash_port": 8504
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
23
docs/_generated/configutils.md
Normal file
23
docs/_generated/configutils.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
## Utils Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} utils
|
||||||
|
:widths: 10 20 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"utils": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
92
docs/_generated/configweather.md
Normal file
92
docs/_generated/configweather.md
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
## Weather Forecast Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} weather
|
||||||
|
:widths: 10 20 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| 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_settings | `EOS_WEATHER__PROVIDER_SETTINGS` | `WeatherCommonProviderSettings` | `rw` | `required` | Provider settings |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"weather": {
|
||||||
|
"provider": "WeatherImport",
|
||||||
|
"provider_settings": {
|
||||||
|
"WeatherImport": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### Common settings for weather data import from file or JSON string
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} weather::provider_settings::WeatherImport
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| import_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | Path to the file to import weather data from. |
|
||||||
|
| import_json | `Optional[str]` | `rw` | `None` | JSON string, dictionary of weather forecast value lists. |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"weather": {
|
||||||
|
"provider_settings": {
|
||||||
|
"WeatherImport": {
|
||||||
|
"import_file_path": null,
|
||||||
|
"import_json": "{\"weather_temp_air\": [18.3, 17.8, 16.9]}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
### Weather Forecast Provider Configuration
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
:::{table} weather::provider_settings
|
||||||
|
:widths: 10 10 5 5 30
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
| Name | Type | Read-Only | Default | Description |
|
||||||
|
| ---- | ---- | --------- | ------- | ----------- |
|
||||||
|
| WeatherImport | `Optional[akkudoktoreos.prediction.weatherimport.WeatherImportCommonSettings]` | `rw` | `None` | WeatherImport settings |
|
||||||
|
:::
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
|
<!-- pyml disable no-emphasis-as-heading -->
|
||||||
|
**Example Input/Output**
|
||||||
|
<!-- pyml enable no-emphasis-as-heading -->
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"weather": {
|
||||||
|
"provider_settings": {
|
||||||
|
"WeatherImport": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
**Version**: `v0.2.0+dev`
|
**Version**: `v0.2.0+dev`
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Description**: This project provides a comprehensive solution for simulating and optimizing an energy system based on renewable energy sources. With a focus on photovoltaic (PV) systems, battery storage (batteries), load management (consumer requirements), heat pumps, electric vehicles, and consideration of electricity price data, this system enables forecasting and optimization of energy flow and costs over a specified period.
|
**Description**: This project provides a comprehensive solution for simulating and optimizing an energy system based on renewable energy sources. With a focus on photovoltaic (PV) systems, battery storage (batteries), load management (consumer requirements), heat pumps, electric vehicles, and consideration of electricity price data, this system enables forecasting and optimization of energy flow and costs over a specified period.
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Base URL**: `No base URL provided.`
|
**Base URL**: `No base URL provided.`
|
||||||
|
|
||||||
@@ -10,11 +12,15 @@
|
|||||||
|
|
||||||
## POST /gesamtlast
|
## POST /gesamtlast
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_gesamtlast_gesamtlast_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_gesamtlast_gesamtlast_post)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_gesamtlast_gesamtlast_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_gesamtlast_gesamtlast_post)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Gesamtlast
|
Fastapi Gesamtlast
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Deprecated: Total Load Prediction with adjustment.
|
Deprecated: Total Load Prediction with adjustment.
|
||||||
|
|
||||||
Endpoint to handle total load prediction adjusted by latest measured data.
|
Endpoint to handle total load prediction adjusted by latest measured data.
|
||||||
@@ -30,7 +36,9 @@ Note:
|
|||||||
'/v1/measurement/series' or
|
'/v1/measurement/series' or
|
||||||
'/v1/measurement/dataframe' or
|
'/v1/measurement/dataframe' or
|
||||||
'/v1/measurement/data'
|
'/v1/measurement/data'
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Request Body**:
|
**Request Body**:
|
||||||
|
|
||||||
@@ -48,11 +56,15 @@ Note:
|
|||||||
|
|
||||||
## GET /gesamtlast_simple
|
## GET /gesamtlast_simple
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_gesamtlast_simple_gesamtlast_simple_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_gesamtlast_simple_gesamtlast_simple_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_gesamtlast_simple_gesamtlast_simple_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_gesamtlast_simple_gesamtlast_simple_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Gesamtlast Simple
|
Fastapi Gesamtlast Simple
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Deprecated: Total Load Prediction.
|
Deprecated: Total Load Prediction.
|
||||||
|
|
||||||
Endpoint to handle total load prediction.
|
Endpoint to handle total load prediction.
|
||||||
@@ -69,7 +81,9 @@ Note:
|
|||||||
'/v1/prediction/update'
|
'/v1/prediction/update'
|
||||||
and then request data with
|
and then request data with
|
||||||
'/v1/prediction/list?key=loadforecast_power_w' instead.
|
'/v1/prediction/list?key=loadforecast_power_w' instead.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -85,18 +99,24 @@ Note:
|
|||||||
|
|
||||||
## POST /optimize
|
## POST /optimize
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_optimize_optimize_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_optimize_optimize_post)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_optimize_optimize_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_optimize_optimize_post)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Optimize
|
Fastapi Optimize
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Deprecated: Optimize.
|
Deprecated: Optimize.
|
||||||
|
|
||||||
Endpoint to handle optimization.
|
Endpoint to handle optimization.
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
Use automatic optimization instead.
|
Use automatic optimization instead.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -120,11 +140,15 @@ Note:
|
|||||||
|
|
||||||
## GET /pvforecast
|
## GET /pvforecast
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_pvforecast_pvforecast_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_pvforecast_pvforecast_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_pvforecast_pvforecast_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_pvforecast_pvforecast_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Pvforecast
|
Fastapi Pvforecast
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Deprecated: PV Forecast Prediction.
|
Deprecated: PV Forecast Prediction.
|
||||||
|
|
||||||
Endpoint to handle PV forecast prediction.
|
Endpoint to handle PV forecast prediction.
|
||||||
@@ -139,7 +163,9 @@ Note:
|
|||||||
and then request data with
|
and then request data with
|
||||||
'/v1/prediction/list?key=pvforecast_ac_power' and
|
'/v1/prediction/list?key=pvforecast_ac_power' and
|
||||||
'/v1/prediction/list?key=pvforecastakkudoktor_temp_air' instead.
|
'/v1/prediction/list?key=pvforecastakkudoktor_temp_air' instead.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -149,11 +175,15 @@ Note:
|
|||||||
|
|
||||||
## GET /strompreis
|
## GET /strompreis
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_strompreis_strompreis_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_strompreis_strompreis_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_strompreis_strompreis_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_strompreis_strompreis_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Strompreis
|
Fastapi Strompreis
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Deprecated: Electricity Market Price Prediction per Wh (€/Wh).
|
Deprecated: Electricity Market Price Prediction per Wh (€/Wh).
|
||||||
|
|
||||||
Electricity prices start at 00.00.00 today and are provided for 48 hours.
|
Electricity prices start at 00.00.00 today and are provided for 48 hours.
|
||||||
@@ -169,7 +199,9 @@ Note:
|
|||||||
and then request data with
|
and then request data with
|
||||||
'/v1/prediction/list?key=elecprice_marketprice_wh' or
|
'/v1/prediction/list?key=elecprice_marketprice_wh' or
|
||||||
'/v1/prediction/list?key=elecprice_marketprice_kwh' instead.
|
'/v1/prediction/list?key=elecprice_marketprice_kwh' instead.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -179,16 +211,22 @@ Note:
|
|||||||
|
|
||||||
## GET /v1/admin/cache
|
## GET /v1/admin/cache
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_admin_cache_get_v1_admin_cache_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_admin_cache_get_v1_admin_cache_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_admin_cache_get_v1_admin_cache_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_admin_cache_get_v1_admin_cache_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Admin Cache Get
|
Fastapi Admin Cache Get
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Current cache management data.
|
Current cache management data.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
data (dict): The management data.
|
data (dict): The management data.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -198,18 +236,24 @@ Returns:
|
|||||||
|
|
||||||
## POST /v1/admin/cache/clear
|
## POST /v1/admin/cache/clear
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_admin_cache_clear_post_v1_admin_cache_clear_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_admin_cache_clear_post_v1_admin_cache_clear_post)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_admin_cache_clear_post_v1_admin_cache_clear_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_admin_cache_clear_post_v1_admin_cache_clear_post)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Admin Cache Clear Post
|
Fastapi Admin Cache Clear Post
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Clear the cache.
|
Clear the cache.
|
||||||
|
|
||||||
Deletes all cache files.
|
Deletes all cache files.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
data (dict): The management data after cleanup.
|
data (dict): The management data after cleanup.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -219,18 +263,24 @@ Returns:
|
|||||||
|
|
||||||
## POST /v1/admin/cache/clear-expired
|
## POST /v1/admin/cache/clear-expired
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_admin_cache_clear_expired_post_v1_admin_cache_clear-expired_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_admin_cache_clear_expired_post_v1_admin_cache_clear-expired_post)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_admin_cache_clear_expired_post_v1_admin_cache_clear-expired_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_admin_cache_clear_expired_post_v1_admin_cache_clear-expired_post)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Admin Cache Clear Expired Post
|
Fastapi Admin Cache Clear Expired Post
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Clear the cache from expired data.
|
Clear the cache from expired data.
|
||||||
|
|
||||||
Deletes expired cache files.
|
Deletes expired cache files.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
data (dict): The management data after cleanup.
|
data (dict): The management data after cleanup.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -240,16 +290,22 @@ Returns:
|
|||||||
|
|
||||||
## POST /v1/admin/cache/load
|
## POST /v1/admin/cache/load
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_admin_cache_load_post_v1_admin_cache_load_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_admin_cache_load_post_v1_admin_cache_load_post)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_admin_cache_load_post_v1_admin_cache_load_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_admin_cache_load_post_v1_admin_cache_load_post)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Admin Cache Load Post
|
Fastapi Admin Cache Load Post
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Load cache management data.
|
Load cache management data.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
data (dict): The management data that was loaded.
|
data (dict): The management data that was loaded.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -259,16 +315,22 @@ Returns:
|
|||||||
|
|
||||||
## POST /v1/admin/cache/save
|
## POST /v1/admin/cache/save
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_admin_cache_save_post_v1_admin_cache_save_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_admin_cache_save_post_v1_admin_cache_save_post)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_admin_cache_save_post_v1_admin_cache_save_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_admin_cache_save_post_v1_admin_cache_save_post)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Admin Cache Save Post
|
Fastapi Admin Cache Save Post
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Save the current cache management data.
|
Save the current cache management data.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
data (dict): The management data that was saved.
|
data (dict): The management data that was saved.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -278,15 +340,21 @@ Returns:
|
|||||||
|
|
||||||
## POST /v1/admin/server/restart
|
## POST /v1/admin/server/restart
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_admin_server_restart_post_v1_admin_server_restart_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_admin_server_restart_post_v1_admin_server_restart_post)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_admin_server_restart_post_v1_admin_server_restart_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_admin_server_restart_post_v1_admin_server_restart_post)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Admin Server Restart Post
|
Fastapi Admin Server Restart Post
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Restart the server.
|
Restart the server.
|
||||||
|
|
||||||
Restart EOS properly by starting a new instance before exiting the old one.
|
Restart EOS properly by starting a new instance before exiting the old one.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -296,13 +364,19 @@ Restart EOS properly by starting a new instance before exiting the old one.
|
|||||||
|
|
||||||
## POST /v1/admin/server/shutdown
|
## POST /v1/admin/server/shutdown
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_admin_server_shutdown_post_v1_admin_server_shutdown_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_admin_server_shutdown_post_v1_admin_server_shutdown_post)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_admin_server_shutdown_post_v1_admin_server_shutdown_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_admin_server_shutdown_post_v1_admin_server_shutdown_post)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Admin Server Shutdown Post
|
Fastapi Admin Server Shutdown Post
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Shutdown the server.
|
Shutdown the server.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -312,16 +386,22 @@ Shutdown the server.
|
|||||||
|
|
||||||
## GET /v1/config
|
## GET /v1/config
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_get_v1_config_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_get_v1_config_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_get_v1_config_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_get_v1_config_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Config Get
|
Fastapi Config Get
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Get the current configuration.
|
Get the current configuration.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
configuration (ConfigEOS): The current configuration.
|
configuration (ConfigEOS): The current configuration.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -331,11 +411,15 @@ Returns:
|
|||||||
|
|
||||||
## PUT /v1/config
|
## PUT /v1/config
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_put_v1_config_put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_put_v1_config_put)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_put_v1_config_put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_put_v1_config_put)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Config Put
|
Fastapi Config Put
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Update the current config with the provided settings.
|
Update the current config with the provided settings.
|
||||||
|
|
||||||
Note that for any setting value that is None or unset, the configuration will fall back to
|
Note that for any setting value that is None or unset, the configuration will fall back to
|
||||||
@@ -347,7 +431,9 @@ Args:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
configuration (ConfigEOS): The current configuration after the write.
|
configuration (ConfigEOS): The current configuration after the write.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Request Body**:
|
**Request Body**:
|
||||||
|
|
||||||
@@ -365,16 +451,22 @@ Returns:
|
|||||||
|
|
||||||
## GET /v1/config/backup
|
## GET /v1/config/backup
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_backup_get_v1_config_backup_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_backup_get_v1_config_backup_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_backup_get_v1_config_backup_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_backup_get_v1_config_backup_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Config Backup Get
|
Fastapi Config Backup Get
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Get the EOS configuration backup identifiers and backup metadata.
|
Get the EOS configuration backup identifiers and backup metadata.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict[str, dict[str, Any]]: Mapping of backup identifiers to metadata.
|
dict[str, dict[str, Any]]: Mapping of backup identifiers to metadata.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -384,16 +476,22 @@ Returns:
|
|||||||
|
|
||||||
## PUT /v1/config/file
|
## PUT /v1/config/file
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_file_put_v1_config_file_put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_file_put_v1_config_file_put)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_file_put_v1_config_file_put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_file_put_v1_config_file_put)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Config File Put
|
Fastapi Config File Put
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Save the current configuration to the EOS configuration file.
|
Save the current configuration to the EOS configuration file.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
configuration (ConfigEOS): The current configuration that was saved.
|
configuration (ConfigEOS): The current configuration that was saved.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -403,16 +501,22 @@ Returns:
|
|||||||
|
|
||||||
## POST /v1/config/reset
|
## POST /v1/config/reset
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_reset_post_v1_config_reset_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_reset_post_v1_config_reset_post)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_reset_post_v1_config_reset_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_reset_post_v1_config_reset_post)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Config Reset Post
|
Fastapi Config Reset Post
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Reset the configuration to the EOS configuration file.
|
Reset the configuration to the EOS configuration file.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
configuration (ConfigEOS): The current configuration after update.
|
configuration (ConfigEOS): The current configuration after update.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -422,16 +526,22 @@ Returns:
|
|||||||
|
|
||||||
## PUT /v1/config/revert
|
## PUT /v1/config/revert
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_revert_put_v1_config_revert_put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_revert_put_v1_config_revert_put)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_revert_put_v1_config_revert_put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_revert_put_v1_config_revert_put)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Config Revert Put
|
Fastapi Config Revert Put
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Revert the configuration to a EOS configuration backup.
|
Revert the configuration to a EOS configuration backup.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
configuration (ConfigEOS): The current configuration after revert.
|
configuration (ConfigEOS): The current configuration after revert.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -447,11 +557,15 @@ Returns:
|
|||||||
|
|
||||||
## GET /v1/config/{path}
|
## GET /v1/config/{path}
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_get_key_v1_config__path__get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_get_key_v1_config__path__get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_get_key_v1_config__path__get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_get_key_v1_config__path__get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Config Get Key
|
Fastapi Config Get Key
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Get the value of a nested key or index in the config model.
|
Get the value of a nested key or index in the config model.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -459,7 +573,9 @@ Args:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
value (Any): The value of the selected nested key.
|
value (Any): The value of the selected nested key.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -475,11 +591,15 @@ Returns:
|
|||||||
|
|
||||||
## PUT /v1/config/{path}
|
## PUT /v1/config/{path}
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_put_key_v1_config__path__put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_put_key_v1_config__path__put)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_put_key_v1_config__path__put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_put_key_v1_config__path__put)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Config Put Key
|
Fastapi Config Put Key
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Update a nested key or index in the config model.
|
Update a nested key or index in the config model.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -488,7 +608,9 @@ Args:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
configuration (ConfigEOS): The current configuration after the update.
|
configuration (ConfigEOS): The current configuration after the update.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -517,13 +639,19 @@ Returns:
|
|||||||
|
|
||||||
## GET /v1/energy-management/optimization/solution
|
## GET /v1/energy-management/optimization/solution
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_energy_management_optimization_solution_get_v1_energy-management_optimization_solution_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_energy_management_optimization_solution_get_v1_energy-management_optimization_solution_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_energy_management_optimization_solution_get_v1_energy-management_optimization_solution_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_energy_management_optimization_solution_get_v1_energy-management_optimization_solution_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Energy Management Optimization Solution Get
|
Fastapi Energy Management Optimization Solution Get
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Get the latest solution of the optimization.
|
Get the latest solution of the optimization.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -533,13 +661,19 @@ Get the latest solution of the optimization.
|
|||||||
|
|
||||||
## GET /v1/energy-management/plan
|
## GET /v1/energy-management/plan
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_energy_management_plan_get_v1_energy-management_plan_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_energy_management_plan_get_v1_energy-management_plan_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_energy_management_plan_get_v1_energy-management_plan_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_energy_management_plan_get_v1_energy-management_plan_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Energy Management Plan Get
|
Fastapi Energy Management Plan Get
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Get the latest energy management plan.
|
Get the latest energy management plan.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -549,13 +683,19 @@ Get the latest energy management plan.
|
|||||||
|
|
||||||
## GET /v1/health
|
## GET /v1/health
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_health_get_v1_health_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_health_get_v1_health_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_health_get_v1_health_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_health_get_v1_health_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Health Get
|
Fastapi Health Get
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Health check endpoint to verify that the EOS server is alive.
|
Health check endpoint to verify that the EOS server is alive.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -565,11 +705,15 @@ Health check endpoint to verify that the EOS server is alive.
|
|||||||
|
|
||||||
## GET /v1/logging/log
|
## GET /v1/logging/log
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_logging_get_log_v1_logging_log_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_logging_get_log_v1_logging_log_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_logging_get_log_v1_logging_log_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_logging_get_log_v1_logging_log_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Logging Get Log
|
Fastapi Logging Get Log
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Get structured log entries from the EOS log file.
|
Get structured log entries from the EOS log file.
|
||||||
|
|
||||||
Filters and returns log entries based on the specified query parameters. The log
|
Filters and returns log entries based on the specified query parameters. The log
|
||||||
@@ -586,7 +730,9 @@ Args:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
JSONResponse: A JSON list of log entries.
|
JSONResponse: A JSON list of log entries.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -614,13 +760,19 @@ Returns:
|
|||||||
|
|
||||||
## PUT /v1/measurement/data
|
## PUT /v1/measurement/data
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_data_put_v1_measurement_data_put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_measurement_data_put_v1_measurement_data_put)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_data_put_v1_measurement_data_put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_measurement_data_put_v1_measurement_data_put)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Measurement Data Put
|
Fastapi Measurement Data Put
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Merge the measurement data given as datetime data into EOS measurements.
|
Merge the measurement data given as datetime data into EOS measurements.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Request Body**:
|
**Request Body**:
|
||||||
|
|
||||||
@@ -638,13 +790,19 @@ Merge the measurement data given as datetime data into EOS measurements.
|
|||||||
|
|
||||||
## PUT /v1/measurement/dataframe
|
## PUT /v1/measurement/dataframe
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_dataframe_put_v1_measurement_dataframe_put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_measurement_dataframe_put_v1_measurement_dataframe_put)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_dataframe_put_v1_measurement_dataframe_put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_measurement_dataframe_put_v1_measurement_dataframe_put)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Measurement Dataframe Put
|
Fastapi Measurement Dataframe Put
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Merge the measurement data given as dataframe into EOS measurements.
|
Merge the measurement data given as dataframe into EOS measurements.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Request Body**:
|
**Request Body**:
|
||||||
|
|
||||||
@@ -662,13 +820,19 @@ Merge the measurement data given as dataframe into EOS measurements.
|
|||||||
|
|
||||||
## GET /v1/measurement/keys
|
## GET /v1/measurement/keys
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_keys_get_v1_measurement_keys_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_measurement_keys_get_v1_measurement_keys_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_keys_get_v1_measurement_keys_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_measurement_keys_get_v1_measurement_keys_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Measurement Keys Get
|
Fastapi Measurement Keys Get
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Get a list of available measurement keys.
|
Get a list of available measurement keys.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -678,13 +842,19 @@ Get a list of available measurement keys.
|
|||||||
|
|
||||||
## GET /v1/measurement/series
|
## GET /v1/measurement/series
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_series_get_v1_measurement_series_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_measurement_series_get_v1_measurement_series_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_series_get_v1_measurement_series_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_measurement_series_get_v1_measurement_series_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Measurement Series Get
|
Fastapi Measurement Series Get
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Get the measurements of given key as series.
|
Get the measurements of given key as series.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -700,13 +870,19 @@ Get the measurements of given key as series.
|
|||||||
|
|
||||||
## PUT /v1/measurement/series
|
## PUT /v1/measurement/series
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_series_put_v1_measurement_series_put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_measurement_series_put_v1_measurement_series_put)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_series_put_v1_measurement_series_put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_measurement_series_put_v1_measurement_series_put)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Measurement Series Put
|
Fastapi Measurement Series Put
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Merge measurement given as series into given key.
|
Merge measurement given as series into given key.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -728,13 +904,19 @@ Merge measurement given as series into given key.
|
|||||||
|
|
||||||
## PUT /v1/measurement/value
|
## PUT /v1/measurement/value
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_value_put_v1_measurement_value_put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_measurement_value_put_v1_measurement_value_put)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_value_put_v1_measurement_value_put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_measurement_value_put_v1_measurement_value_put)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Measurement Value Put
|
Fastapi Measurement Value Put
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Merge the measurement of given key and value into EOS measurements at given datetime.
|
Merge the measurement of given key and value into EOS measurements at given datetime.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -754,11 +936,15 @@ Merge the measurement of given key and value into EOS measurements at given date
|
|||||||
|
|
||||||
## GET /v1/prediction/dataframe
|
## GET /v1/prediction/dataframe
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_dataframe_get_v1_prediction_dataframe_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_prediction_dataframe_get_v1_prediction_dataframe_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_dataframe_get_v1_prediction_dataframe_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_prediction_dataframe_get_v1_prediction_dataframe_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Prediction Dataframe Get
|
Fastapi Prediction Dataframe Get
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Get prediction for given key within given date range as series.
|
Get prediction for given key within given date range as series.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -768,7 +954,9 @@ Args:
|
|||||||
end_datetime (Optional[str]: Ending datetime (exclusive).
|
end_datetime (Optional[str]: Ending datetime (exclusive).
|
||||||
|
|
||||||
Defaults to end datetime of latest prediction.
|
Defaults to end datetime of latest prediction.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -790,11 +978,15 @@ Defaults to end datetime of latest prediction.
|
|||||||
|
|
||||||
## PUT /v1/prediction/import/{provider_id}
|
## PUT /v1/prediction/import/{provider_id}
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_import_provider_v1_prediction_import__provider_id__put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_prediction_import_provider_v1_prediction_import__provider_id__put)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_import_provider_v1_prediction_import__provider_id__put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_prediction_import_provider_v1_prediction_import__provider_id__put)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Prediction Import Provider
|
Fastapi Prediction Import Provider
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Import prediction for given provider ID.
|
Import prediction for given provider ID.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -802,7 +994,9 @@ Args:
|
|||||||
data: Prediction data.
|
data: Prediction data.
|
||||||
force_enable: Update data even if provider is disabled.
|
force_enable: Update data even if provider is disabled.
|
||||||
Defaults to False.
|
Defaults to False.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -841,13 +1035,19 @@ Args:
|
|||||||
|
|
||||||
## GET /v1/prediction/keys
|
## GET /v1/prediction/keys
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_keys_get_v1_prediction_keys_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_prediction_keys_get_v1_prediction_keys_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_keys_get_v1_prediction_keys_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_prediction_keys_get_v1_prediction_keys_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Prediction Keys Get
|
Fastapi Prediction Keys Get
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Get a list of available prediction keys.
|
Get a list of available prediction keys.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Responses**:
|
**Responses**:
|
||||||
|
|
||||||
@@ -857,11 +1057,15 @@ Get a list of available prediction keys.
|
|||||||
|
|
||||||
## GET /v1/prediction/list
|
## GET /v1/prediction/list
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_list_get_v1_prediction_list_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_prediction_list_get_v1_prediction_list_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_list_get_v1_prediction_list_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_prediction_list_get_v1_prediction_list_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Prediction List Get
|
Fastapi Prediction List Get
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Get prediction for given key within given date range as value list.
|
Get prediction for given key within given date range as value list.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -872,7 +1076,9 @@ Args:
|
|||||||
Defaults to end datetime of latest prediction.
|
Defaults to end datetime of latest prediction.
|
||||||
interval (Optional[str]): Time duration for each interval.
|
interval (Optional[str]): Time duration for each interval.
|
||||||
Defaults to 1 hour.
|
Defaults to 1 hour.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -894,16 +1100,22 @@ Args:
|
|||||||
|
|
||||||
## GET /v1/prediction/providers
|
## GET /v1/prediction/providers
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_providers_get_v1_prediction_providers_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_prediction_providers_get_v1_prediction_providers_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_providers_get_v1_prediction_providers_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_prediction_providers_get_v1_prediction_providers_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Prediction Providers Get
|
Fastapi Prediction Providers Get
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Get a list of available prediction providers.
|
Get a list of available prediction providers.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
enabled (bool): Return enabled/disabled providers. If unset, return all providers.
|
enabled (bool): Return enabled/disabled providers. If unset, return all providers.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -919,11 +1131,15 @@ Args:
|
|||||||
|
|
||||||
## GET /v1/prediction/series
|
## GET /v1/prediction/series
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_series_get_v1_prediction_series_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_prediction_series_get_v1_prediction_series_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_series_get_v1_prediction_series_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_prediction_series_get_v1_prediction_series_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Prediction Series Get
|
Fastapi Prediction Series Get
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Get prediction for given key within given date range as series.
|
Get prediction for given key within given date range as series.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -932,7 +1148,9 @@ Args:
|
|||||||
Defaults to start datetime of latest prediction.
|
Defaults to start datetime of latest prediction.
|
||||||
end_datetime (Optional[str]: Ending datetime (exclusive).
|
end_datetime (Optional[str]: Ending datetime (exclusive).
|
||||||
Defaults to end datetime of latest prediction.
|
Defaults to end datetime of latest prediction.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -952,11 +1170,15 @@ Args:
|
|||||||
|
|
||||||
## POST /v1/prediction/update
|
## POST /v1/prediction/update
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_update_v1_prediction_update_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_prediction_update_v1_prediction_update_post)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_update_v1_prediction_update_post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_prediction_update_v1_prediction_update_post)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Prediction Update
|
Fastapi Prediction Update
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Update predictions for all providers.
|
Update predictions for all providers.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -964,7 +1186,9 @@ Args:
|
|||||||
Defaults to False.
|
Defaults to False.
|
||||||
force_enable: Update data even if provider is disabled.
|
force_enable: Update data even if provider is disabled.
|
||||||
Defaults to False.
|
Defaults to False.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -982,11 +1206,15 @@ Args:
|
|||||||
|
|
||||||
## POST /v1/prediction/update/{provider_id}
|
## POST /v1/prediction/update/{provider_id}
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_update_provider_v1_prediction_update__provider_id__post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_prediction_update_provider_v1_prediction_update__provider_id__post)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_update_provider_v1_prediction_update__provider_id__post), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_prediction_update_provider_v1_prediction_update__provider_id__post)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Prediction Update Provider
|
Fastapi Prediction Update Provider
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Update predictions for given provider ID.
|
Update predictions for given provider ID.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -995,7 +1223,9 @@ Args:
|
|||||||
Defaults to False.
|
Defaults to False.
|
||||||
force_enable: Update data even if provider is disabled.
|
force_enable: Update data even if provider is disabled.
|
||||||
Defaults to False.
|
Defaults to False.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -1015,16 +1245,22 @@ Args:
|
|||||||
|
|
||||||
## GET /v1/resource/status
|
## GET /v1/resource/status
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_devices_status_get_v1_resource_status_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_devices_status_get_v1_resource_status_get)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_devices_status_get_v1_resource_status_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_devices_status_get_v1_resource_status_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Devices Status Get
|
Fastapi Devices Status Get
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Get the latest status of a resource/ device.
|
Get the latest status of a resource/ device.
|
||||||
|
|
||||||
Return:
|
Return:
|
||||||
latest_status: The latest status of a resource/ device.
|
latest_status: The latest status of a resource/ device.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -1042,16 +1278,22 @@ Return:
|
|||||||
|
|
||||||
## PUT /v1/resource/status
|
## PUT /v1/resource/status
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/fastapi_devices_status_put_v1_resource_status_put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_devices_status_put_v1_resource_status_put)
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_devices_status_put_v1_resource_status_put), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_devices_status_put_v1_resource_status_put)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Fastapi Devices Status Put
|
Fastapi Devices Status Put
|
||||||
|
|
||||||
```
|
<!-- pyml disable line-length -->
|
||||||
|
```python
|
||||||
|
"""
|
||||||
Update the status of a resource/ device.
|
Update the status of a resource/ device.
|
||||||
|
|
||||||
Return:
|
Return:
|
||||||
latest_status: The latest status of a resource/ device.
|
latest_status: The latest status of a resource/ device.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
|
|
||||||
@@ -1105,7 +1347,9 @@ Return:
|
|||||||
|
|
||||||
## GET /visualization_results.pdf
|
## GET /visualization_results.pdf
|
||||||
|
|
||||||
|
<!-- pyml disable line-length -->
|
||||||
**Links**: [local](http://localhost:8503/docs#/default/get_pdf_visualization_results_pdf_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/get_pdf_visualization_results_pdf_get)
|
**Links**: [local](http://localhost:8503/docs#/default/get_pdf_visualization_results_pdf_get), [eos](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/get_pdf_visualization_results_pdf_get)
|
||||||
|
<!-- pyml enable line-length -->
|
||||||
|
|
||||||
Get Pdf
|
Get Pdf
|
||||||
|
|
||||||
@@ -1114,3 +1358,5 @@ Get Pdf
|
|||||||
- **200**: Successful Response
|
- **200**: Successful Response
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
Auto generated from openapi.json.
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ extensions = [
|
|||||||
"sphinx.ext.autodoc",
|
"sphinx.ext.autodoc",
|
||||||
"sphinx.ext.autosummary",
|
"sphinx.ext.autosummary",
|
||||||
"sphinx.ext.napoleon",
|
"sphinx.ext.napoleon",
|
||||||
|
"sphinx.ext.todo",
|
||||||
"sphinx_rtd_theme",
|
"sphinx_rtd_theme",
|
||||||
"myst_parser",
|
"myst_parser",
|
||||||
"sphinx_tabs.tabs",
|
"sphinx_tabs.tabs",
|
||||||
|
|||||||
@@ -2519,7 +2519,7 @@
|
|||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "ConfigEOS",
|
"title": "ConfigEOS",
|
||||||
"description": "Singleton configuration handler for the EOS application.\n\nConfigEOS extends `SettingsEOS` with support for default configuration paths and automatic\ninitialization.\n\n`ConfigEOS` ensures that only one instance of the class is created throughout the application,\nallowing consistent access to EOS configuration settings. This singleton instance loads\nconfiguration data from a predefined set of directories or creates a default configuration if\nnone is found.\n\nInitialization Process:\n - Upon instantiation, the singleton instance attempts to load a configuration file in this order:\n 1. The directory specified by the `EOS_CONFIG_DIR` environment variable\n 2. The directory specified by the `EOS_DIR` environment variable.\n 3. A platform specific default directory for EOS.\n 4. The current working directory.\n - The first available configuration file found in these directories is loaded.\n - If no configuration file is found, a default configuration file is created in the platform\n specific default directory, and default settings are loaded into it.\n\nAttributes from the loaded configuration are accessible directly as instance attributes of\n`ConfigEOS`, providing a centralized, shared configuration object for EOS.\n\nSingleton Behavior:\n - This class uses the `SingletonMixin` to ensure that all requests for `ConfigEOS` return\n the same instance, which contains the most up-to-date configuration. Modifying the configuration\n in one part of the application reflects across all references to this class.\n\nAttributes:\n config_folder_path (Optional[Path]): Path to the configuration directory.\n config_file_path (Optional[Path]): Path to the configuration file.\n\nRaises:\n FileNotFoundError: If no configuration file is found, and creating a default configuration fails.\n\nExample:\n To initialize and access configuration attributes (only one instance is created):\n ```python\n config_eos = ConfigEOS() # Always returns the same instance\n print(config_eos.prediction.hours) # Access a setting from the loaded configuration\n ```"
|
"description": "Singleton configuration handler for the EOS application.\n\nConfigEOS extends `SettingsEOS` with support for default configuration paths and automatic\ninitialization.\n\n`ConfigEOS` ensures that only one instance of the class is created throughout the application,\nallowing consistent access to EOS configuration settings. This singleton instance loads\nconfiguration data from a predefined set of directories or creates a default configuration if\nnone is found.\n\nInitialization Process:\n - Upon instantiation, the singleton instance attempts to load a configuration file in this order:\n 1. The directory specified by the `EOS_CONFIG_DIR` environment variable\n 2. The directory specified by the `EOS_DIR` environment variable.\n 3. A platform specific default directory for EOS.\n 4. The current working directory.\n - The first available configuration file found in these directories is loaded.\n - If no configuration file is found, a default configuration file is created in the platform\n specific default directory, and default settings are loaded into it.\n\nAttributes from the loaded configuration are accessible directly as instance attributes of\n`ConfigEOS`, providing a centralized, shared configuration object for EOS.\n\nSingleton Behavior:\n - This class uses the `SingletonMixin` to ensure that all requests for `ConfigEOS` return\n the same instance, which contains the most up-to-date configuration. Modifying the configuration\n in one part of the application reflects across all references to this class.\n\nAttributes:\n config_folder_path (Optional[Path]): Path to the configuration directory.\n config_file_path (Optional[Path]): Path to the configuration file.\n\nRaises:\n FileNotFoundError: If no configuration file is found, and creating a default configuration fails.\n\nExample:\n To initialize and access configuration attributes (only one instance is created):\n .. code-block:: python\n\n config_eos = ConfigEOS() # Always returns the same instance\n print(config_eos.prediction.hours) # Access a setting from the loaded configuration"
|
||||||
},
|
},
|
||||||
"DDBCActuatorStatus": {
|
"DDBCActuatorStatus": {
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -7153,7 +7153,7 @@
|
|||||||
},
|
},
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "PydanticDateTimeData",
|
"title": "PydanticDateTimeData",
|
||||||
"description": "Pydantic model for time series data with consistent value lengths.\n\nThis model validates a dictionary where:\n- Keys are strings representing data series names\n- Values are lists of numeric or string values\n- Special keys 'start_datetime' and 'interval' can contain string values\nfor time series indexing\n- All value lists must have the same length\n\nExample:\n {\n \"start_datetime\": \"2024-01-01 00:00:00\", # optional\n \"interval\": \"1 Hour\", # optional\n \"loadforecast_power_w\": [20.5, 21.0, 22.1],\n \"load_min\": [18.5, 19.0, 20.1]\n }"
|
"description": "Pydantic model for time series data with consistent value lengths.\n\nThis model validates a dictionary where:\n- Keys are strings representing data series names\n- Values are lists of numeric or string values\n- Special keys 'start_datetime' and 'interval' can contain string values\nfor time series indexing\n- All value lists must have the same length\n\nExample:\n .. code-block:: python\n\n {\n \"start_datetime\": \"2024-01-01 00:00:00\", # optional\n \"interval\": \"1 Hour\", # optional\n \"loadforecast_power_w\": [20.5, 21.0, 22.1],\n \"load_min\": [18.5, 19.0, 20.1]\n }"
|
||||||
},
|
},
|
||||||
"PydanticDateTimeDataFrame": {
|
"PydanticDateTimeDataFrame": {
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Type, Union
|
from typing import Any, Optional, Type, Union, get_args
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from pydantic.fields import ComputedFieldInfo, FieldInfo
|
from pydantic.fields import ComputedFieldInfo, FieldInfo
|
||||||
@@ -24,13 +24,29 @@ undocumented_types: dict[PydanticBaseModel, tuple[str, list[str]]] = dict()
|
|||||||
global_config_dict: dict[str, Any] = dict()
|
global_config_dict: dict[str, Any] = dict()
|
||||||
|
|
||||||
|
|
||||||
def get_title(config: PydanticBaseModel) -> str:
|
def get_model_class_from_annotation(field_type: Any) -> type[PydanticBaseModel] | None:
|
||||||
|
"""Given a type annotation (possibly Optional or Union), return the first Pydantic model class."""
|
||||||
|
origin = getattr(field_type, "__origin__", None)
|
||||||
|
if origin is Union:
|
||||||
|
# unwrap Union/Optional
|
||||||
|
for arg in get_args(field_type):
|
||||||
|
cls = get_model_class_from_annotation(arg)
|
||||||
|
if cls is not None:
|
||||||
|
return cls
|
||||||
|
return None
|
||||||
|
elif isinstance(field_type, type) and issubclass(field_type, PydanticBaseModel):
|
||||||
|
return field_type
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_title(config: type[PydanticBaseModel]) -> str:
|
||||||
if config.__doc__ is None:
|
if config.__doc__ is None:
|
||||||
raise NameError(f"Missing docstring: {config}")
|
raise NameError(f"Missing docstring: {config}")
|
||||||
return config.__doc__.strip().splitlines()[0].strip(".")
|
return config.__doc__.strip().splitlines()[0].strip(".")
|
||||||
|
|
||||||
|
|
||||||
def get_body(config: PydanticBaseModel) -> str:
|
def get_body(config: type[PydanticBaseModel]) -> str:
|
||||||
if config.__doc__ is None:
|
if config.__doc__ is None:
|
||||||
raise NameError(f"Missing docstring: {config}")
|
raise NameError(f"Missing docstring: {config}")
|
||||||
return textwrap.dedent("\n".join(config.__doc__.strip().splitlines()[1:])).strip()
|
return textwrap.dedent("\n".join(config.__doc__.strip().splitlines()[1:])).strip()
|
||||||
@@ -124,7 +140,7 @@ def get_model_structure_from_examples(
|
|||||||
|
|
||||||
|
|
||||||
def create_model_from_examples(
|
def create_model_from_examples(
|
||||||
model_class: PydanticBaseModel, multiple: bool
|
model_class: type[PydanticBaseModel], multiple: bool
|
||||||
) -> list[PydanticBaseModel]:
|
) -> list[PydanticBaseModel]:
|
||||||
"""Create a model instance with default or example values, respecting constraints."""
|
"""Create a model instance with default or example values, respecting constraints."""
|
||||||
return [
|
return [
|
||||||
@@ -163,7 +179,7 @@ def get_type_name(field_type: type) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def generate_config_table_md(
|
def generate_config_table_md(
|
||||||
config: PydanticBaseModel,
|
config: type[PydanticBaseModel],
|
||||||
toplevel_keys: list[str],
|
toplevel_keys: list[str],
|
||||||
prefix: str,
|
prefix: str,
|
||||||
toplevel: bool = False,
|
toplevel: bool = False,
|
||||||
@@ -199,22 +215,28 @@ def generate_config_table_md(
|
|||||||
table += "\n\n"
|
table += "\n\n"
|
||||||
|
|
||||||
table += (
|
table += (
|
||||||
|
"<!-- pyml disable line-length -->\n"
|
||||||
":::{table} "
|
":::{table} "
|
||||||
+ f"{'::'.join(toplevel_keys)}\n:widths: 10 {env_width}10 5 5 30\n:align: left\n\n"
|
+ f"{'::'.join(toplevel_keys)}\n:widths: 10 {env_width}10 5 5 30\n:align: left\n\n"
|
||||||
)
|
)
|
||||||
table += f"| Name {env_header}| Type | Read-Only | Default | Description |\n"
|
table += f"| Name {env_header}| Type | Read-Only | Default | Description |\n"
|
||||||
table += f"| ---- {env_header_underline}| ---- | --------- | ------- | ----------- |\n"
|
table += f"| ---- {env_header_underline}| ---- | --------- | ------- | ----------- |\n"
|
||||||
|
|
||||||
for field_name, field_info in list(config.model_fields.items()) + list(
|
|
||||||
config.model_computed_fields.items()
|
fields = {}
|
||||||
):
|
for field_name, field_info in config.model_fields.items():
|
||||||
|
fields[field_name] = field_info
|
||||||
|
for field_name, field_info in config.model_computed_fields.items():
|
||||||
|
fields[field_name] = field_info
|
||||||
|
for field_name in sorted(fields.keys()):
|
||||||
|
field_info = fields[field_name]
|
||||||
regular_field = isinstance(field_info, FieldInfo)
|
regular_field = isinstance(field_info, FieldInfo)
|
||||||
|
|
||||||
config_name = field_name if extra_config else field_name.upper()
|
config_name = field_name if extra_config else field_name.upper()
|
||||||
field_type = field_info.annotation if regular_field else field_info.return_type
|
field_type = field_info.annotation if regular_field else field_info.return_type
|
||||||
default_value = get_default_value(field_info, regular_field)
|
default_value = get_default_value(field_info, regular_field)
|
||||||
description = field_info.description if field_info.description else "-"
|
description = config.field_description(field_name)
|
||||||
deprecated = field_info.deprecated if field_info.deprecated else None
|
deprecated = config.field_deprecated(field_name)
|
||||||
read_only = "rw" if regular_field else "ro"
|
read_only = "rw" if regular_field else "ro"
|
||||||
type_name = get_type_name(field_type)
|
type_name = get_type_name(field_type)
|
||||||
|
|
||||||
@@ -270,7 +292,7 @@ def generate_config_table_md(
|
|||||||
undocumented_types.setdefault(new_type, (info[0], info[1]))
|
undocumented_types.setdefault(new_type, (info[0], info[1]))
|
||||||
|
|
||||||
if toplevel:
|
if toplevel:
|
||||||
table += ":::\n\n" # Add an empty line after the table
|
table += ":::\n<!-- pyml enable line-length -->\n\n" # Add an empty line after the table
|
||||||
|
|
||||||
has_examples_list = toplevel_keys[-1] == "list"
|
has_examples_list = toplevel_keys[-1] == "list"
|
||||||
instance_list = create_model_from_examples(config, has_examples_list)
|
instance_list = create_model_from_examples(config, has_examples_list)
|
||||||
@@ -288,9 +310,13 @@ def generate_config_table_md(
|
|||||||
same_output = ins_out_dict_list == ins_dict_list
|
same_output = ins_out_dict_list == ins_dict_list
|
||||||
same_output_str = "/Output" if same_output else ""
|
same_output_str = "/Output" if same_output else ""
|
||||||
|
|
||||||
table += f"#{heading_level} Example Input{same_output_str}\n\n"
|
# -- code block heading
|
||||||
table += "```{eval-rst}\n"
|
table += "<!-- pyml disable no-emphasis-as-heading -->\n"
|
||||||
table += ".. code-block:: json\n\n"
|
table += f"**Example Input{same_output_str}**\n"
|
||||||
|
table += "<!-- pyml enable no-emphasis-as-heading -->\n\n"
|
||||||
|
# -- code block
|
||||||
|
table += "<!-- pyml disable line-length -->\n"
|
||||||
|
table += "```json\n"
|
||||||
if has_examples_list:
|
if has_examples_list:
|
||||||
input_dict = build_nested_structure(toplevel_keys[:-1], ins_dict_list)
|
input_dict = build_nested_structure(toplevel_keys[:-1], ins_dict_list)
|
||||||
if not extra_config:
|
if not extra_config:
|
||||||
@@ -300,20 +326,24 @@ def generate_config_table_md(
|
|||||||
if not extra_config:
|
if not extra_config:
|
||||||
global_config_dict[toplevel_keys[0]] = ins_dict_list[0]
|
global_config_dict[toplevel_keys[0]] = ins_dict_list[0]
|
||||||
table += textwrap.indent(json.dumps(input_dict, indent=4), " ")
|
table += textwrap.indent(json.dumps(input_dict, indent=4), " ")
|
||||||
table += "\n"
|
table += "\n```\n<!-- pyml enable line-length -->\n\n"
|
||||||
table += "```\n\n"
|
# -- end code block
|
||||||
|
|
||||||
if not same_output:
|
if not same_output:
|
||||||
table += f"#{heading_level} Example Output\n\n"
|
# -- code block heading
|
||||||
table += "```{eval-rst}\n"
|
table += "<!-- pyml disable no-emphasis-as-heading -->\n"
|
||||||
table += ".. code-block:: json\n\n"
|
table += f"**Example Output**\n"
|
||||||
|
table += "<!-- pyml enable no-emphasis-as-heading -->\n\n"
|
||||||
|
# -- code block
|
||||||
|
table += "<!-- pyml disable line-length -->\n"
|
||||||
|
table += "```json\n"
|
||||||
if has_examples_list:
|
if has_examples_list:
|
||||||
output_dict = build_nested_structure(toplevel_keys[:-1], ins_out_dict_list)
|
output_dict = build_nested_structure(toplevel_keys[:-1], ins_out_dict_list)
|
||||||
else:
|
else:
|
||||||
output_dict = build_nested_structure(toplevel_keys, ins_out_dict_list[0])
|
output_dict = build_nested_structure(toplevel_keys, ins_out_dict_list[0])
|
||||||
table += textwrap.indent(json.dumps(output_dict, indent=4), " ")
|
table += textwrap.indent(json.dumps(output_dict, indent=4), " ")
|
||||||
table += "\n"
|
table += "\n```\n<!-- pyml enable line-length -->\n\n"
|
||||||
table += "```\n\n"
|
# -- end code block
|
||||||
|
|
||||||
while undocumented_types:
|
while undocumented_types:
|
||||||
extra_config_type, extra_info = undocumented_types.popitem()
|
extra_config_type, extra_info = undocumented_types.popitem()
|
||||||
@@ -325,7 +355,7 @@ def generate_config_table_md(
|
|||||||
return table
|
return table
|
||||||
|
|
||||||
|
|
||||||
def generate_config_md(config_eos: ConfigEOS) -> str:
|
def generate_config_md(file_path: Optional[Union[str, Path]], config_eos: ConfigEOS) -> str:
|
||||||
"""Generate configuration specification in Markdown with extra tables for prefixed values.
|
"""Generate configuration specification in Markdown with extra tables for prefixed values.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -337,44 +367,103 @@ def generate_config_md(config_eos: ConfigEOS) -> str:
|
|||||||
)
|
)
|
||||||
GeneralSettings._config_folder_path = config_eos.general.config_file_path.parent
|
GeneralSettings._config_folder_path = config_eos.general.config_file_path.parent
|
||||||
|
|
||||||
markdown = "# Configuration Table\n\n"
|
markdown = ""
|
||||||
|
|
||||||
# Generate tables for each top level config
|
if file_path:
|
||||||
for field_name, field_info in config_eos.__class__.model_fields.items():
|
file_path = Path(file_path)
|
||||||
field_type = field_info.annotation
|
# -- table of content
|
||||||
markdown += generate_config_table_md(
|
markdown += "```{toctree}\n"
|
||||||
field_type, [field_name], f"EOS_{field_name.upper()}__", True
|
markdown += ":maxdepth: 1\n"
|
||||||
|
markdown += ":caption: Configuration Table\n\n"
|
||||||
|
else:
|
||||||
|
markdown += "# Configuration Table\n\n"
|
||||||
|
markdown += (
|
||||||
|
"The configuration table describes all the configuration options of Akkudoktor-EOS\n\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Generate tables for each top level config
|
||||||
|
for field_name in sorted(config_eos.__class__.model_fields.keys()):
|
||||||
|
field_info = config_eos.__class__.model_fields[field_name]
|
||||||
|
field_type = field_info.annotation
|
||||||
|
model_class = get_model_class_from_annotation(field_type)
|
||||||
|
if model_class is None:
|
||||||
|
raise ValueError(f"Can not find class of top level field {field_name}.")
|
||||||
|
table = generate_config_table_md(
|
||||||
|
model_class, [field_name], f"EOS_{field_name.upper()}__", True
|
||||||
|
)
|
||||||
|
if file_path:
|
||||||
|
# Write table to extra document
|
||||||
|
table_path = file_path.with_name(file_path.stem + f"{field_name.lower()}.md")
|
||||||
|
write_to_file(table_path, table)
|
||||||
|
markdown += f"../_generated/{table_path.name}\n"
|
||||||
|
else:
|
||||||
|
# We will write to stdout
|
||||||
|
markdown += "---\n\n"
|
||||||
|
markdown += table
|
||||||
|
|
||||||
|
# Generate full example
|
||||||
|
example = ""
|
||||||
# Full config
|
# Full config
|
||||||
markdown += "## Full example Config\n\n"
|
example += "## Full example Config\n\n"
|
||||||
markdown += "```{eval-rst}\n"
|
# -- code block
|
||||||
markdown += ".. code-block:: json\n\n"
|
example += "<!-- pyml disable line-length -->\n"
|
||||||
|
example += "```json\n"
|
||||||
# Test for valid config first
|
# Test for valid config first
|
||||||
config_eos.merge_settings_from_dict(global_config_dict)
|
config_eos.merge_settings_from_dict(global_config_dict)
|
||||||
markdown += textwrap.indent(json.dumps(global_config_dict, indent=4), " ")
|
example += textwrap.indent(json.dumps(global_config_dict, indent=4), " ")
|
||||||
markdown += "\n"
|
example += "\n"
|
||||||
|
example += "```\n<!-- pyml enable line-length -->\n\n"
|
||||||
|
# -- end code block end
|
||||||
|
if file_path:
|
||||||
|
example_path = file_path.with_name(file_path.stem + f"example.md")
|
||||||
|
write_to_file(example_path, example)
|
||||||
|
markdown += f"../_generated/{example_path.name}\n"
|
||||||
markdown += "```\n\n"
|
markdown += "```\n\n"
|
||||||
|
# -- end table of content
|
||||||
|
else:
|
||||||
|
markdown += "---\n\n"
|
||||||
|
markdown += example
|
||||||
|
|
||||||
# Assure there is no double \n at end of file
|
# Assure there is no double \n at end of file
|
||||||
markdown = markdown.rstrip("\n")
|
markdown = markdown.rstrip("\n")
|
||||||
markdown += "\n"
|
markdown += "\n"
|
||||||
|
|
||||||
|
markdown += "\nAuto generated from source code.\n"
|
||||||
|
|
||||||
|
# Write markdown to file or stdout
|
||||||
|
write_to_file(file_path, markdown)
|
||||||
|
|
||||||
|
return markdown
|
||||||
|
|
||||||
|
|
||||||
|
def write_to_file(file_path: Optional[Union[str, Path]], config_md: str):
|
||||||
|
if os.name == "nt":
|
||||||
|
config_md = config_md.replace("\\\\", "/")
|
||||||
|
|
||||||
# Assure log path does not leak to documentation
|
# Assure log path does not leak to documentation
|
||||||
markdown = re.sub(
|
config_md = re.sub(
|
||||||
r'(?<=["\'])/[^"\']*/output/eos\.log(?=["\'])',
|
r'(?<=["\'])/[^"\']*/output/eos\.log(?=["\'])',
|
||||||
'/home/user/.local/share/net.akkudoktoreos.net/output/eos.log',
|
'/home/user/.local/share/net.akkudoktor.eos/output/eos.log',
|
||||||
markdown
|
config_md
|
||||||
)
|
)
|
||||||
|
|
||||||
# Assure timezone name does not leak to documentation
|
# Assure timezone name does not leak to documentation
|
||||||
tz_name = to_datetime().timezone_name
|
tz_name = to_datetime().timezone_name
|
||||||
markdown = re.sub(re.escape(tz_name), "Europe/Berlin", markdown, flags=re.IGNORECASE)
|
config_md = re.sub(re.escape(tz_name), "Europe/Berlin", config_md, flags=re.IGNORECASE)
|
||||||
# Also replace UTC, as GitHub CI always is on UTC
|
# Also replace UTC, as GitHub CI always is on UTC
|
||||||
markdown = re.sub(re.escape("UTC"), "Europe/Berlin", markdown, flags=re.IGNORECASE)
|
config_md = re.sub(re.escape("UTC"), "Europe/Berlin", config_md, flags=re.IGNORECASE)
|
||||||
|
|
||||||
|
# Assure no extra lines at end of file
|
||||||
|
config_md = config_md.rstrip("\n")
|
||||||
|
config_md += "\n"
|
||||||
|
|
||||||
return markdown
|
if file_path:
|
||||||
|
# Write to file
|
||||||
|
with open(Path(file_path), "w", encoding="utf-8", newline="\n") as f:
|
||||||
|
f.write(config_md)
|
||||||
|
else:
|
||||||
|
# Write to std output
|
||||||
|
print(config_md)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@@ -384,23 +473,14 @@ def main():
|
|||||||
"--output-file",
|
"--output-file",
|
||||||
type=str,
|
type=str,
|
||||||
default=None,
|
default=None,
|
||||||
help="File to write the Configuration Specification to",
|
help="File to write the top level configuration specification to.",
|
||||||
)
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
config_eos = get_config()
|
config_eos = get_config()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
config_md = generate_config_md(config_eos)
|
config_md = generate_config_md(args.output_file, config_eos)
|
||||||
if os.name == "nt":
|
|
||||||
config_md = config_md.replace("\\\\", "/")
|
|
||||||
if args.output_file:
|
|
||||||
# Write to file
|
|
||||||
with open(args.output_file, "w", encoding="utf-8", newline="\n") as f:
|
|
||||||
f.write(config_md)
|
|
||||||
else:
|
|
||||||
# Write to std output
|
|
||||||
print(config_md)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error during Configuration Specification generation: {e}", file=sys.stderr)
|
print(f"Error during Configuration Specification generation: {e}", file=sys.stderr)
|
||||||
|
|||||||
@@ -194,6 +194,8 @@ def format_endpoint(path: str, method: str, details: dict, devel: bool = False)
|
|||||||
|
|
||||||
markdown = f"## {method.upper()} {path}\n\n"
|
markdown = f"## {method.upper()} {path}\n\n"
|
||||||
|
|
||||||
|
# -- links
|
||||||
|
markdown += "<!-- pyml disable line-length -->\n"
|
||||||
markdown += f"**Links**: {local_path}, {akkudoktoreos_main_path}"
|
markdown += f"**Links**: {local_path}, {akkudoktoreos_main_path}"
|
||||||
if devel:
|
if devel:
|
||||||
# Add link to akkudoktor branch the development has used
|
# Add link to akkudoktor branch the development has used
|
||||||
@@ -206,7 +208,8 @@ def format_endpoint(path: str, method: str, details: dict, devel: bool = False)
|
|||||||
+ link_method
|
+ link_method
|
||||||
)
|
)
|
||||||
markdown += f", {akkudoktoreos_base_path}"
|
markdown += f", {akkudoktoreos_base_path}"
|
||||||
markdown += "\n\n"
|
markdown += "\n<!-- pyml enable line-length -->\n\n"
|
||||||
|
# -- links end
|
||||||
|
|
||||||
summary = details.get("summary", None)
|
summary = details.get("summary", None)
|
||||||
if summary:
|
if summary:
|
||||||
@@ -214,9 +217,14 @@ def format_endpoint(path: str, method: str, details: dict, devel: bool = False)
|
|||||||
|
|
||||||
description = details.get("description", None)
|
description = details.get("description", None)
|
||||||
if description:
|
if description:
|
||||||
markdown += "```\n"
|
# -- code block
|
||||||
markdown += f"{description}"
|
markdown += "<!-- pyml disable line-length -->\n"
|
||||||
markdown += "\n```\n\n"
|
markdown += "```python\n"
|
||||||
|
markdown += '"""\n'
|
||||||
|
markdown += f"{description}\n"
|
||||||
|
markdown += '"""\n'
|
||||||
|
markdown += "```\n<!-- pyml enable line-length -->\n\n"
|
||||||
|
# -- end code block end
|
||||||
|
|
||||||
markdown += format_parameters(details.get("parameters", []))
|
markdown += format_parameters(details.get("parameters", []))
|
||||||
markdown += format_request_body(details.get("requestBody", {}).get("content", {}))
|
markdown += format_request_body(details.get("requestBody", {}).get("content", {}))
|
||||||
@@ -239,7 +247,11 @@ def openapi_to_markdown(openapi_json: dict, devel: bool = False) -> str:
|
|||||||
info = extract_info(openapi_json)
|
info = extract_info(openapi_json)
|
||||||
markdown = f"# {info['title']}\n\n"
|
markdown = f"# {info['title']}\n\n"
|
||||||
markdown += f"**Version**: `{info['version']}`\n\n"
|
markdown += f"**Version**: `{info['version']}`\n\n"
|
||||||
markdown += f"**Description**: {info['description']}\n\n"
|
# -- description
|
||||||
|
markdown += "<!-- pyml disable line-length -->\n"
|
||||||
|
markdown += f"**Description**: {info['description']}\n"
|
||||||
|
markdown += "<!-- pyml enable line-length -->\n\n"
|
||||||
|
# -- end description
|
||||||
markdown += f"**Base URL**: `{info['base_url']}`\n\n"
|
markdown += f"**Base URL**: `{info['base_url']}`\n\n"
|
||||||
|
|
||||||
security_schemes = openapi_json.get("components", {}).get("securitySchemes", {})
|
security_schemes = openapi_json.get("components", {}).get("securitySchemes", {})
|
||||||
@@ -257,6 +269,8 @@ def openapi_to_markdown(openapi_json: dict, devel: bool = False) -> str:
|
|||||||
markdown = markdown.rstrip("\n")
|
markdown = markdown.rstrip("\n")
|
||||||
markdown += "\n"
|
markdown += "\n"
|
||||||
|
|
||||||
|
markdown += "\nAuto generated from openapi.json.\n"
|
||||||
|
|
||||||
return markdown
|
return markdown
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -287,10 +287,10 @@ class ConfigEOS(SingletonMixin, SettingsEOSDefaults):
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
To initialize and access configuration attributes (only one instance is created):
|
To initialize and access configuration attributes (only one instance is created):
|
||||||
```python
|
.. code-block:: python
|
||||||
|
|
||||||
config_eos = ConfigEOS() # Always returns the same instance
|
config_eos = ConfigEOS() # Always returns the same instance
|
||||||
print(config_eos.prediction.hours) # Access a setting from the loaded configuration
|
print(config_eos.prediction.hours) # Access a setting from the loaded configuration
|
||||||
```
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -461,9 +461,12 @@ class ConfigEOS(SingletonMixin, SettingsEOSDefaults):
|
|||||||
ValidationError: If the data contains invalid values for the defined fields.
|
ValidationError: If the data contains invalid values for the defined fields.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
>>> config = get_config()
|
.. code-block:: python
|
||||||
>>> new_data = {"prediction": {"hours": 24}, "server": {"port": 8000}}
|
|
||||||
>>> config.merge_settings_from_dict(new_data)
|
config = get_config()
|
||||||
|
new_data = {"prediction": {"hours": 24}, "server": {"port": 8000}}
|
||||||
|
config.merge_settings_from_dict(new_data)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._setup(**merge_models(self, data))
|
self._setup(**merge_models(self, data))
|
||||||
|
|
||||||
@@ -518,8 +521,7 @@ class ConfigEOS(SingletonMixin, SettingsEOSDefaults):
|
|||||||
The returned dictionary uses `backup_id` (suffix) as keys. The value for
|
The returned dictionary uses `backup_id` (suffix) as keys. The value for
|
||||||
each key is a dictionary including:
|
each key is a dictionary including:
|
||||||
- ``storage_time``: The file modification timestamp in ISO-8601 format.
|
- ``storage_time``: The file modification timestamp in ISO-8601 format.
|
||||||
- ``version``: Version information found in the backup file
|
- ``version``: Version information found in the backup file (defaults to ``"unknown"``).
|
||||||
(defaults to ``"unknown"``).
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict[str, dict[str, Any]]: Mapping of backup identifiers to metadata.
|
dict[str, dict[str, Any]]: Mapping of backup identifiers to metadata.
|
||||||
|
|||||||
@@ -90,7 +90,10 @@ class CacheEnergyManagementStore(SingletonMixin):
|
|||||||
the application lifecycle.
|
the application lifecycle.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
>>> cache = CacheEnergyManagementStore()
|
.. code-block:: python
|
||||||
|
|
||||||
|
cache = CacheEnergyManagementStore()
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if hasattr(self, "_initialized"):
|
if hasattr(self, "_initialized"):
|
||||||
return
|
return
|
||||||
@@ -112,7 +115,10 @@ class CacheEnergyManagementStore(SingletonMixin):
|
|||||||
AttributeError: If the cache object does not have the requested method.
|
AttributeError: If the cache object does not have the requested method.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
>>> result = cache.get("key")
|
.. code-block:: python
|
||||||
|
|
||||||
|
result = cache.get("key")
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# This will return a method of the target cache, or raise an AttributeError
|
# This will return a method of the target cache, or raise an AttributeError
|
||||||
target_attr = getattr(self.cache, name)
|
target_attr = getattr(self.cache, name)
|
||||||
@@ -134,7 +140,10 @@ class CacheEnergyManagementStore(SingletonMixin):
|
|||||||
KeyError: If the key does not exist in the cache.
|
KeyError: If the key does not exist in the cache.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
>>> value = cache["user_data"]
|
.. code-block:: python
|
||||||
|
|
||||||
|
value = cache["user_data"]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return CacheEnergyManagementStore.cache[key]
|
return CacheEnergyManagementStore.cache[key]
|
||||||
|
|
||||||
@@ -146,7 +155,10 @@ class CacheEnergyManagementStore(SingletonMixin):
|
|||||||
value (Any): The value to store.
|
value (Any): The value to store.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
>>> cache["user_data"] = {"name": "Alice", "age": 30}
|
.. code-block:: python
|
||||||
|
|
||||||
|
cache["user_data"] = {"name": "Alice", "age": 30}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
CacheEnergyManagementStore.cache[key] = value
|
CacheEnergyManagementStore.cache[key] = value
|
||||||
|
|
||||||
@@ -166,7 +178,10 @@ class CacheEnergyManagementStore(SingletonMixin):
|
|||||||
management system run).
|
management system run).
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
>>> cache.clear()
|
.. code-block:: python
|
||||||
|
|
||||||
|
cache.clear()
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if hasattr(self.cache, "clear") and callable(getattr(self.cache, "clear")):
|
if hasattr(self.cache, "clear") and callable(getattr(self.cache, "clear")):
|
||||||
CacheEnergyManagementStore.cache.clear()
|
CacheEnergyManagementStore.cache.clear()
|
||||||
@@ -248,12 +263,15 @@ class CacheFileStore(ConfigMixin, SingletonMixin):
|
|||||||
with their associated keys and dates.
|
with their associated keys and dates.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
>>> cache_store = CacheFileStore()
|
.. code-block:: python
|
||||||
>>> cache_store.create('example_file')
|
|
||||||
>>> cache_file = cache_store.get('example_file')
|
cache_store = CacheFileStore()
|
||||||
>>> cache_file.write('Some data')
|
cache_store.create('example_file')
|
||||||
>>> cache_file.seek(0)
|
cache_file = cache_store.get('example_file')
|
||||||
>>> print(cache_file.read()) # Output: 'Some data'
|
cache_file.write('Some data')
|
||||||
|
cache_file.seek(0)
|
||||||
|
print(cache_file.read()) # Output: 'Some data'
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
@@ -462,10 +480,13 @@ class CacheFileStore(ConfigMixin, SingletonMixin):
|
|||||||
file_obj: A file-like object representing the cache file.
|
file_obj: A file-like object representing the cache file.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
>>> cache_file = cache_store.create('example_file', suffix='.txt')
|
.. code-block:: python
|
||||||
>>> cache_file.write('Some cached data')
|
|
||||||
>>> cache_file.seek(0)
|
cache_file = cache_store.create('example_file', suffix='.txt')
|
||||||
>>> print(cache_file.read()) # Output: 'Some cached data'
|
cache_file.write('Some cached data')
|
||||||
|
cache_file.seek(0)
|
||||||
|
print(cache_file.read()) # Output: 'Some cached data'
|
||||||
|
|
||||||
"""
|
"""
|
||||||
cache_file_key, until_datetime_dt, ttl_duration = self._generate_cache_file_key(
|
cache_file_key, until_datetime_dt, ttl_duration = self._generate_cache_file_key(
|
||||||
key, until_datetime=until_datetime, until_date=until_date, with_ttl=with_ttl
|
key, until_datetime=until_datetime, until_date=until_date, with_ttl=with_ttl
|
||||||
@@ -514,7 +535,10 @@ class CacheFileStore(ConfigMixin, SingletonMixin):
|
|||||||
ValueError: If the key is already in store.
|
ValueError: If the key is already in store.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
>>> cache_store.set('example_file', io.BytesIO(b'Some binary data'))
|
.. code-block:: python
|
||||||
|
|
||||||
|
cache_store.set('example_file', io.BytesIO(b'Some binary data'))
|
||||||
|
|
||||||
"""
|
"""
|
||||||
cache_file_key, until_datetime_dt, ttl_duration = self._generate_cache_file_key(
|
cache_file_key, until_datetime_dt, ttl_duration = self._generate_cache_file_key(
|
||||||
key, until_datetime=until_datetime, until_date=until_date, with_ttl=with_ttl
|
key, until_datetime=until_datetime, until_date=until_date, with_ttl=with_ttl
|
||||||
@@ -570,10 +594,13 @@ class CacheFileStore(ConfigMixin, SingletonMixin):
|
|||||||
file_obj: The file-like cache object, or None if no file is found.
|
file_obj: The file-like cache object, or None if no file is found.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
>>> cache_file = cache_store.get('example_file')
|
.. code-block:: python
|
||||||
>>> if cache_file:
|
|
||||||
>>> cache_file.seek(0)
|
cache_file = cache_store.get('example_file')
|
||||||
>>> print(cache_file.read()) # Output: Cached data (if exists)
|
if cache_file:
|
||||||
|
cache_file.seek(0)
|
||||||
|
print(cache_file.read()) # Output: Cached data (if exists)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if until_datetime or until_date:
|
if until_datetime or until_date:
|
||||||
until_datetime, _ttl_duration = self._until_datetime_by_options(
|
until_datetime, _ttl_duration = self._until_datetime_by_options(
|
||||||
@@ -852,13 +879,15 @@ def cache_in_file(
|
|||||||
A decorated function that caches its result in a temporary file.
|
A decorated function that caches its result in a temporary file.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
>>> from datetime import date
|
.. code-block:: python
|
||||||
>>> @cache_in_file(suffix='.txt')
|
|
||||||
>>> def expensive_computation(until_date=None):
|
from datetime import date
|
||||||
>>> # Perform some expensive computation
|
@cache_in_file(suffix='.txt')
|
||||||
>>> return 'Some large result'
|
def expensive_computation(until_date=None):
|
||||||
>>>
|
# Perform some expensive computation
|
||||||
>>> result = expensive_computation(until_date=date.today())
|
return 'Some large result'
|
||||||
|
|
||||||
|
result = expensive_computation(until_date=date.today())
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
- The cache key is based on the function arguments after excluding those in `ignore_params`.
|
- The cache key is based on the function arguments after excluding those in `ignore_params`.
|
||||||
|
|||||||
@@ -39,11 +39,12 @@ class ConfigMixin:
|
|||||||
config (ConfigEOS): Property to access the global EOS configuration.
|
config (ConfigEOS): Property to access the global EOS configuration.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```python
|
.. code-block:: python
|
||||||
|
|
||||||
class MyEOSClass(ConfigMixin):
|
class MyEOSClass(ConfigMixin):
|
||||||
def my_method(self):
|
def my_method(self):
|
||||||
if self.config.myconfigval:
|
if self.config.myconfigval:
|
||||||
```
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classproperty
|
@classproperty
|
||||||
@@ -78,12 +79,13 @@ class MeasurementMixin:
|
|||||||
measurement (Measurement): Property to access the global EOS measurement data.
|
measurement (Measurement): Property to access the global EOS measurement data.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```python
|
.. code-block:: python
|
||||||
|
|
||||||
class MyOptimizationClass(MeasurementMixin):
|
class MyOptimizationClass(MeasurementMixin):
|
||||||
def analyze_mymeasurement(self):
|
def analyze_mymeasurement(self):
|
||||||
measurement_data = self.measurement.mymeasurement
|
measurement_data = self.measurement.mymeasurement
|
||||||
# Perform analysis
|
# Perform analysis
|
||||||
```
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classproperty
|
@classproperty
|
||||||
@@ -118,12 +120,13 @@ class PredictionMixin:
|
|||||||
prediction (Prediction): Property to access the global EOS prediction data.
|
prediction (Prediction): Property to access the global EOS prediction data.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```python
|
.. code-block:: python
|
||||||
|
|
||||||
class MyOptimizationClass(PredictionMixin):
|
class MyOptimizationClass(PredictionMixin):
|
||||||
def analyze_myprediction(self):
|
def analyze_myprediction(self):
|
||||||
prediction_data = self.prediction.mypredictionresult
|
prediction_data = self.prediction.mypredictionresult
|
||||||
# Perform analysis
|
# Perform analysis
|
||||||
```
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classproperty
|
@classproperty
|
||||||
@@ -159,12 +162,13 @@ class EnergyManagementSystemMixin:
|
|||||||
ems (EnergyManagementSystem): Property to access the global EOS energy management system.
|
ems (EnergyManagementSystem): Property to access the global EOS energy management system.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```python
|
.. code-block:: python
|
||||||
|
|
||||||
class MyOptimizationClass(EnergyManagementSystemMixin):
|
class MyOptimizationClass(EnergyManagementSystemMixin):
|
||||||
def analyze_myprediction(self):
|
def analyze_myprediction(self):
|
||||||
ems_data = self.ems.the_ems_method()
|
ems_data = self.ems.the_ems_method()
|
||||||
# Perform analysis
|
# Perform analysis
|
||||||
```
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classproperty
|
@classproperty
|
||||||
@@ -224,6 +228,8 @@ class SingletonMixin:
|
|||||||
- Avoid using `__init__` to reinitialize the singleton instance after it has been created.
|
- Avoid using `__init__` to reinitialize the singleton instance after it has been created.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
class MySingletonModel(SingletonMixin, PydanticBaseModel):
|
class MySingletonModel(SingletonMixin, PydanticBaseModel):
|
||||||
name: str
|
name: str
|
||||||
|
|
||||||
@@ -240,6 +246,7 @@ class SingletonMixin:
|
|||||||
|
|
||||||
assert instance1 is instance2 # True
|
assert instance1 is instance2 # True
|
||||||
print(instance1.name) # Output: "Instance 1"
|
print(instance1.name) # Output: "Instance 1"
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_lock: ClassVar[threading.Lock] = threading.Lock()
|
_lock: ClassVar[threading.Lock] = threading.Lock()
|
||||||
|
|||||||
@@ -432,6 +432,8 @@ class DataSequence(DataBase, MutableSequence):
|
|||||||
Derived classes have to provide their own records field with correct record type set.
|
Derived classes have to provide their own records field with correct record type set.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
# 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, json_schema_extra={ "description": "List of data records" })
|
records: List[DerivedDataRecord] = Field(default_factory=list, json_schema_extra={ "description": "List of data records" })
|
||||||
@@ -446,6 +448,7 @@ class DataSequence(DataBase, MutableSequence):
|
|||||||
|
|
||||||
# Convert to Pandas Series
|
# Convert to Pandas Series
|
||||||
series = seq.key_to_series('temperature')
|
series = seq.key_to_series('temperature')
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# To be overloaded by derived classes.
|
# To be overloaded by derived classes.
|
||||||
@@ -737,9 +740,12 @@ class DataSequence(DataBase, MutableSequence):
|
|||||||
**kwargs: Key-value pairs as keyword arguments
|
**kwargs: Key-value pairs as keyword arguments
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
>>> update_value(date, 'temperature', 25.5)
|
.. code-block:: python
|
||||||
>>> update_value(date, {'temperature': 25.5, 'humidity': 80})
|
|
||||||
>>> update_value(date, temperature=25.5, humidity=80)
|
update_value(date, 'temperature', 25.5)
|
||||||
|
update_value(date, {'temperature': 25.5, 'humidity': 80})
|
||||||
|
update_value(date, temperature=25.5, humidity=80)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Process input arguments into a dictionary
|
# Process input arguments into a dictionary
|
||||||
values: Dict[str, Any] = {}
|
values: Dict[str, Any] = {}
|
||||||
@@ -1378,15 +1384,18 @@ class DataImportMixin:
|
|||||||
"""Mixin class for import of generic data.
|
"""Mixin class for import of generic data.
|
||||||
|
|
||||||
This class is designed to handle generic data provided in the form of a key-value dictionary.
|
This class is designed to handle generic data provided in the form of a key-value dictionary.
|
||||||
|
|
||||||
- **Keys**: Represent identifiers from the record keys of a specific data.
|
- **Keys**: Represent identifiers from the record keys of a specific data.
|
||||||
- **Values**: Are lists of data values starting at a specified `start_datetime`, where
|
- **Values**: Are lists of data values starting at a specified start_datetime, where
|
||||||
each value corresponds to a subsequent time interval (e.g., hourly).
|
each value corresponds to a subsequent time interval (e.g., hourly).
|
||||||
|
|
||||||
Two special keys are handled. `start_datetime` may be used to defined the starting datetime of
|
Two special keys are handled. start_datetime may be used to defined the starting datetime of
|
||||||
the values. `ìnterval` may be used to define the fixed time interval between two values.
|
the values. ìnterval may be used to define the fixed time interval between two values.
|
||||||
|
|
||||||
|
On import self.update_value(datetime, key, value) is called which has to be provided.
|
||||||
|
Also self.ems_start_datetime may be necessary as a default in case start_datetime is not
|
||||||
|
given.
|
||||||
|
|
||||||
On import `self.update_value(datetime, key, value)` is called which has to be provided.
|
|
||||||
Also `self.ems_start_datetime` may be necessary as a default in case `start_datetime`is not given.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Attributes required but defined elsehere.
|
# Attributes required but defined elsehere.
|
||||||
@@ -1418,16 +1427,20 @@ class DataImportMixin:
|
|||||||
Behavior:
|
Behavior:
|
||||||
- Skips invalid timestamps during DST spring forward transitions.
|
- Skips invalid timestamps during DST spring forward transitions.
|
||||||
- Includes both instances of repeated timestamps during DST fall back transitions.
|
- Includes both instances of repeated timestamps during DST fall back transitions.
|
||||||
- Ensures the list contains exactly `value_count` entries.
|
- Ensures the list contains exactly 'value_count' entries.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
>>> start_datetime = pendulum.datetime(2024, 11, 3, 0, 0, tz="America/New_York")
|
.. code-block:: python
|
||||||
>>> import_datetimes(start_datetime, 5)
|
|
||||||
|
start_datetime = pendulum.datetime(2024, 11, 3, 0, 0, tz="America/New_York")
|
||||||
|
import_datetimes(start_datetime, 5)
|
||||||
|
|
||||||
[(DateTime(2024, 11, 3, 0, 0, tzinfo=Timezone('America/New_York')), 0),
|
[(DateTime(2024, 11, 3, 0, 0, tzinfo=Timezone('America/New_York')), 0),
|
||||||
(DateTime(2024, 11, 3, 1, 0, tzinfo=Timezone('America/New_York')), 1),
|
(DateTime(2024, 11, 3, 1, 0, tzinfo=Timezone('America/New_York')), 1),
|
||||||
(DateTime(2024, 11, 3, 1, 0, tzinfo=Timezone('America/New_York')), 1), # Repeated hour
|
(DateTime(2024, 11, 3, 1, 0, tzinfo=Timezone('America/New_York')), 1), # Repeated hour
|
||||||
(DateTime(2024, 11, 3, 2, 0, tzinfo=Timezone('America/New_York')), 2),
|
(DateTime(2024, 11, 3, 2, 0, tzinfo=Timezone('America/New_York')), 2),
|
||||||
(DateTime(2024, 11, 3, 3, 0, tzinfo=Timezone('America/New_York')), 3)]
|
(DateTime(2024, 11, 3, 3, 0, tzinfo=Timezone('America/New_York')), 3)]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
timestamps_with_indices: List[Tuple[DateTime, int]] = []
|
timestamps_with_indices: List[Tuple[DateTime, int]] = []
|
||||||
|
|
||||||
@@ -1665,17 +1678,18 @@ class DataImportMixin:
|
|||||||
JSONDecodeError: If the file content is not valid JSON.
|
JSONDecodeError: If the file content is not valid JSON.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
Given a JSON string with the following content:
|
Given a JSON string with the following content and `key_prefix = "load"`, only the
|
||||||
```json
|
"loadforecast_power_w" key will be processed even though both keys are in the record.
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"start_datetime": "2024-11-10 00:00:00"
|
"start_datetime": "2024-11-10 00:00:00",
|
||||||
"interval": "30 minutes"
|
"interval": "30 minutes",
|
||||||
"loadforecast_power_w": [20.5, 21.0, 22.1],
|
"loadforecast_power_w": [20.5, 21.0, 22.1],
|
||||||
"other_xyz: [10.5, 11.0, 12.1],
|
"other_xyz: [10.5, 11.0, 12.1]
|
||||||
}
|
}
|
||||||
```
|
|
||||||
and `key_prefix = "load"`, only the "loadforecast_power_w" key will be processed even though
|
|
||||||
both keys are in the record.
|
|
||||||
"""
|
"""
|
||||||
# Try pandas dataframe with orient="split"
|
# Try pandas dataframe with orient="split"
|
||||||
try:
|
try:
|
||||||
@@ -1741,15 +1755,16 @@ class DataImportMixin:
|
|||||||
JSONDecodeError: If the file content is not valid JSON.
|
JSONDecodeError: If the file content is not valid JSON.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
Given a JSON file with the following content:
|
Given a JSON file with the following content and `key_prefix = "load"`, only the
|
||||||
```json
|
"loadforecast_power_w" key will be processed even though both keys are in the record.
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"loadforecast_power_w": [20.5, 21.0, 22.1],
|
"loadforecast_power_w": [20.5, 21.0, 22.1],
|
||||||
"other_xyz: [10.5, 11.0, 12.1],
|
"other_xyz: [10.5, 11.0, 12.1],
|
||||||
}
|
}
|
||||||
```
|
|
||||||
and `key_prefix = "load"`, only the "loadforecast_power_w" key will be processed even though
|
|
||||||
both keys are in the record.
|
|
||||||
"""
|
"""
|
||||||
with import_file_path.open("r", encoding="utf-8", newline=None) as import_file:
|
with import_file_path.open("r", encoding="utf-8", newline=None) as import_file:
|
||||||
import_str = import_file.read()
|
import_str = import_file.read()
|
||||||
@@ -1762,6 +1777,7 @@ class DataImportProvider(DataImportMixin, DataProvider):
|
|||||||
"""Abstract base class for data providers that import generic data.
|
"""Abstract base class for data providers that import generic data.
|
||||||
|
|
||||||
This class is designed to handle generic data provided in the form of a key-value dictionary.
|
This class is designed to handle generic data provided in the form of a key-value dictionary.
|
||||||
|
|
||||||
- **Keys**: Represent identifiers from the record keys of a specific data.
|
- **Keys**: Represent identifiers from the record keys of a specific data.
|
||||||
- **Values**: Are lists of data values starting at a specified `start_datetime`, where
|
- **Values**: Are lists of data values starting at a specified `start_datetime`, where
|
||||||
each value corresponds to a subsequent time interval (e.g., hourly).
|
each value corresponds to a subsequent time interval (e.g., hourly).
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ class classproperty:
|
|||||||
the class rather than any instance of the class.
|
the class rather than any instance of the class.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
class MyClass:
|
class MyClass:
|
||||||
_value = 42
|
_value = 42
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,12 @@ These enhancements facilitate the use of Pydantic models in applications requiri
|
|||||||
datetime fields and consistent data serialization.
|
datetime fields and consistent data serialization.
|
||||||
|
|
||||||
Key Features:
|
Key Features:
|
||||||
|
|
||||||
- Custom type adapter for `pendulum.DateTime` fields with automatic serialization to ISO 8601 strings.
|
- Custom type adapter for `pendulum.DateTime` fields with automatic serialization to ISO 8601 strings.
|
||||||
- Utility methods for converting models to and from dictionaries and JSON strings.
|
- Utility methods for converting models to and from dictionaries and JSON strings.
|
||||||
- Validation tools for maintaining data consistency, including specialized support for
|
- Validation tools for maintaining data consistency, including specialized support for
|
||||||
pandas DataFrames and Series with datetime indexes.
|
pandas DataFrames and Series with datetime indexes.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
@@ -157,6 +159,8 @@ class PydanticModelNestedValueMixin:
|
|||||||
or an invalid transition is made (such as an attribute on a non-model).
|
or an invalid transition is made (such as an attribute on a non-model).
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
class Address(PydanticBaseModel):
|
class Address(PydanticBaseModel):
|
||||||
city: str
|
city: str
|
||||||
|
|
||||||
@@ -167,6 +171,7 @@ class PydanticModelNestedValueMixin:
|
|||||||
user = User(name="Alice", address=Address(city="NY"))
|
user = User(name="Alice", address=Address(city="NY"))
|
||||||
user._validate_path_structure("address/city") # OK
|
user._validate_path_structure("address/city") # OK
|
||||||
user._validate_path_structure("address/zipcode") # Raises ValueError
|
user._validate_path_structure("address/zipcode") # Raises ValueError
|
||||||
|
|
||||||
"""
|
"""
|
||||||
path_elements = path.strip("/").split("/")
|
path_elements = path.strip("/").split("/")
|
||||||
# The model we are currently working on
|
# The model we are currently working on
|
||||||
@@ -264,7 +269,8 @@ class PydanticModelNestedValueMixin:
|
|||||||
IndexError: If a list index is out of bounds or invalid.
|
IndexError: If a list index is out of bounds or invalid.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```python
|
.. code-block:: python
|
||||||
|
|
||||||
class Address(PydanticBaseModel):
|
class Address(PydanticBaseModel):
|
||||||
city: str
|
city: str
|
||||||
|
|
||||||
@@ -275,7 +281,7 @@ class PydanticModelNestedValueMixin:
|
|||||||
user = User(name="Alice", address=Address(city="New York"))
|
user = User(name="Alice", address=Address(city="New York"))
|
||||||
city = user.get_nested_value("address/city")
|
city = user.get_nested_value("address/city")
|
||||||
print(city) # Output: "New York"
|
print(city) # Output: "New York"
|
||||||
```
|
|
||||||
"""
|
"""
|
||||||
path_elements = path.strip("/").split("/")
|
path_elements = path.strip("/").split("/")
|
||||||
model: Any = self
|
model: Any = self
|
||||||
@@ -318,7 +324,8 @@ class PydanticModelNestedValueMixin:
|
|||||||
TypeError: If a missing field cannot be initialized.
|
TypeError: If a missing field cannot be initialized.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```python
|
.. code-block:: python
|
||||||
|
|
||||||
class Address(PydanticBaseModel):
|
class Address(PydanticBaseModel):
|
||||||
city: Optional[str]
|
city: Optional[str]
|
||||||
|
|
||||||
@@ -333,7 +340,7 @@ class PydanticModelNestedValueMixin:
|
|||||||
|
|
||||||
print(user.address.city) # Output: "Los Angeles"
|
print(user.address.city) # Output: "Los Angeles"
|
||||||
print(user.settings) # Output: {'theme': 'dark'}
|
print(user.settings) # Output: {'theme': 'dark'}
|
||||||
```
|
|
||||||
"""
|
"""
|
||||||
path = path.strip("/")
|
path = path.strip("/")
|
||||||
# Store old value (if possible)
|
# Store old value (if possible)
|
||||||
@@ -753,18 +760,21 @@ class PydanticBaseModel(PydanticModelNestedValueMixin, BaseModel):
|
|||||||
gracefully by returning an empty dictionary.
|
gracefully by returning an empty dictionary.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
>>> class User(Base):
|
.. code-block:: python
|
||||||
... name: str = Field(
|
|
||||||
... json_schema_extra={"description": "User name"}
|
class User(Base):
|
||||||
... )
|
name: str = Field(
|
||||||
...
|
json_schema_extra={"description": "User name"}
|
||||||
>>> field = User.model_fields["name"]
|
)
|
||||||
>>> User.get_field_extra_dict(field)
|
|
||||||
|
field = User.model_fields["name"]
|
||||||
|
User.get_field_extra_dict(field)
|
||||||
{'description': 'User name'}
|
{'description': 'User name'}
|
||||||
|
|
||||||
>>> missing = User.model_fields.get("unknown", None)
|
missing = User.model_fields.get("unknown", None)
|
||||||
>>> User.get_field_extra_dict(missing) if missing else {}
|
User.get_field_extra_dict(missing) if missing else {}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if model_field is None:
|
if model_field is None:
|
||||||
return {}
|
return {}
|
||||||
@@ -873,12 +883,15 @@ class PydanticDateTimeData(RootModel):
|
|||||||
- All value lists must have the same length
|
- All value lists must have the same length
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
{
|
{
|
||||||
"start_datetime": "2024-01-01 00:00:00", # optional
|
"start_datetime": "2024-01-01 00:00:00", # optional
|
||||||
"interval": "1 Hour", # optional
|
"interval": "1 Hour", # optional
|
||||||
"loadforecast_power_w": [20.5, 21.0, 22.1],
|
"loadforecast_power_w": [20.5, 21.0, 22.1],
|
||||||
"load_min": [18.5, 19.0, 20.1]
|
"load_min": [18.5, 19.0, 20.1]
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
root: Dict[str, Union[str, List[Union[float, int, str, None]]]]
|
root: Dict[str, Union[str, List[Union[float, int, str, None]]]]
|
||||||
@@ -1275,9 +1288,12 @@ class PydanticDateTimeSeries(PydanticBaseModel):
|
|||||||
ValueError: If series index is not datetime type.
|
ValueError: If series index is not datetime type.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
>>> dates = pd.date_range('2024-01-01', periods=3)
|
.. code-block:: python
|
||||||
>>> s = pd.Series([1.1, 2.2, 3.3], index=dates)
|
|
||||||
>>> model = PydanticDateTimeSeries.from_series(s)
|
dates = pd.date_range('2024-01-01', periods=3)
|
||||||
|
s = pd.Series([1.1, 2.2, 3.3], index=dates)
|
||||||
|
model = PydanticDateTimeSeries.from_series(s)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
index = pd.Index([to_datetime(dt, as_string=True, in_timezone=tz) for dt in series.index])
|
index = pd.Index([to_datetime(dt, as_string=True, in_timezone=tz) for dt in series.index])
|
||||||
series.index = index
|
series.index = index
|
||||||
|
|||||||
@@ -171,25 +171,28 @@ class Battery:
|
|||||||
|
|
||||||
Two **exclusive** modes:
|
Two **exclusive** modes:
|
||||||
|
|
||||||
Mode 1:
|
**Mode 1:**
|
||||||
- `wh is not None` and `charge_factor == 0`
|
|
||||||
→ The raw requested charge energy is `wh` (pre-efficiency).
|
- `wh is not None` and `charge_factor == 0`
|
||||||
→ If remaining capacity is insufficient, charging is automatically limited.
|
- The raw requested charge energy is `wh` (pre-efficiency).
|
||||||
→ No exception is raised due to capacity limits.
|
- If remaining capacity is insufficient, charging is automatically limited.
|
||||||
|
- No exception is raised due to capacity limits.
|
||||||
|
|
||||||
|
**Mode 2:**
|
||||||
|
|
||||||
Mode 2:
|
|
||||||
- `wh is None` and `charge_factor > 0`
|
- `wh is None` and `charge_factor > 0`
|
||||||
→ The raw requested energy is `max_charge_power_w * charge_factor`.
|
- The raw requested energy is `max_charge_power_w * charge_factor`.
|
||||||
→ If the request exceeds remaining capacity, the algorithm tries to
|
- If the request exceeds remaining capacity, the algorithm tries to find a lower
|
||||||
find a lower charge_factor that is compatible. If such a charge factor
|
`charge_factor` that is compatible. If such a charge factor exists, this hour’s
|
||||||
exists, this hour’s charge_factor is replaced.
|
`charge_factor` is replaced.
|
||||||
→ If no charge factor can accommodate charging, the request is ignored
|
- If no charge factor can accommodate charging, the request is ignored (``(0.0, 0.0)`` is
|
||||||
(`(0.0, 0.0)` is returned) and a penalty is applied elsewhere.
|
returned) and a penalty is applied elsewhere.
|
||||||
|
|
||||||
Charging is constrained by:
|
Charging is constrained by:
|
||||||
• Available SoC headroom (max_soc_wh − soc_wh)
|
|
||||||
• max_charge_power_w
|
- Available SoC headroom (``max_soc_wh − soc_wh``)
|
||||||
• charging_efficiency
|
- ``max_charge_power_w``
|
||||||
|
- ``charging_efficiency``
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
wh (float | None):
|
wh (float | None):
|
||||||
|
|||||||
@@ -212,8 +212,7 @@ class GeneticSolution(ConfigMixin, GeneticParametersBaseModel):
|
|||||||
discharge_allowed (bool): Whether discharging is permitted.
|
discharge_allowed (bool): Whether discharging is permitted.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
tuple[BatteryOperationMode, float]:
|
tuple[BatteryOperationMode, float]: A tuple containing
|
||||||
A tuple containing:
|
|
||||||
- `BatteryOperationMode`: the representative high-level operation mode.
|
- `BatteryOperationMode`: the representative high-level operation mode.
|
||||||
- `float`: the operation factor corresponding to the active signal.
|
- `float`: the operation factor corresponding to the active signal.
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ class PredictionSequence(DataSequence):
|
|||||||
Derived classes have to provide their own records field with correct record type set.
|
Derived classes have to provide their own records field with correct record type set.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
# 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, json_schema_extra={ "description": "List of prediction records" })
|
records: List[DerivedPredictionRecord] = Field(default_factory=list, json_schema_extra={ "description": "List of prediction records" })
|
||||||
@@ -84,6 +86,7 @@ class PredictionSequence(DataSequence):
|
|||||||
|
|
||||||
# Convert to Pandas Series
|
# Convert to Pandas Series
|
||||||
series = seq.key_to_series('temperature')
|
series = seq.key_to_series('temperature')
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# To be overloaded by derived classes.
|
# To be overloaded by derived classes.
|
||||||
@@ -224,6 +227,7 @@ class PredictionImportProvider(PredictionProvider, DataImportProvider):
|
|||||||
"""Abstract base class for prediction providers that import prediction data.
|
"""Abstract base class for prediction providers that import prediction data.
|
||||||
|
|
||||||
This class is designed to handle prediction data provided in the form of a key-value dictionary.
|
This class is designed to handle prediction data provided in the form of a key-value dictionary.
|
||||||
|
|
||||||
- **Keys**: Represent identifiers from the record keys of a specific prediction.
|
- **Keys**: Represent identifiers from the record keys of a specific prediction.
|
||||||
- **Values**: Are lists of prediction values starting at a specified `start_datetime`, where
|
- **Values**: Are lists of prediction values starting at a specified `start_datetime`, where
|
||||||
each value corresponds to a subsequent time interval (e.g., hourly).
|
each value corresponds to a subsequent time interval (e.g., hourly).
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ Classes:
|
|||||||
PVForecastAkkudoktor: Primary class to manage PV power forecasts, handle data retrieval, caching, and integration with Akkudoktor.net.
|
PVForecastAkkudoktor: Primary class to manage PV power forecasts, handle data retrieval, caching, and integration with Akkudoktor.net.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
# Set up the configuration with necessary fields for URL generation
|
# Set up the configuration with necessary fields for URL generation
|
||||||
settings_data = {
|
settings_data = {
|
||||||
"general": {
|
"general": {
|
||||||
|
|||||||
@@ -117,17 +117,25 @@ class WeatherClearOutside(WeatherProvider):
|
|||||||
|
|
||||||
Workflow:
|
Workflow:
|
||||||
1. **Retrieve Web Content**: Uses a helper method to fetch or retrieve cached ClearOutside HTML content.
|
1. **Retrieve Web Content**: Uses a helper method to fetch or retrieve cached ClearOutside HTML content.
|
||||||
|
|
||||||
2. **Extract Forecast Date and Timezone**:
|
2. **Extract Forecast Date and Timezone**:
|
||||||
- Parses the forecast's start and end dates and the UTC offset from the "Generated" header.
|
- Parses the forecast's start and end dates and the UTC offset from the "Generated"
|
||||||
|
header.
|
||||||
|
|
||||||
3. **Extract Weather Data**:
|
3. **Extract Weather Data**:
|
||||||
- For each day in the 7-day forecast, the function finds detailed weather parameters
|
- For each day in the 7-day forecast, the function finds detailed weather parameters
|
||||||
and associates values for each hour.
|
and associates values for each hour.
|
||||||
- Parameters include cloud cover, temperature, humidity, visibility, and precipitation type, among others.
|
- Parameters include cloud cover, temperature, humidity, visibility, and
|
||||||
|
precipitation type, among others.
|
||||||
|
|
||||||
4. **Irradiance Calculation**:
|
4. **Irradiance Calculation**:
|
||||||
- Calculates irradiance (GHI, DNI, DHI) values using cloud cover data and the `pvlib` library.
|
- Calculates irradiance (GHI, DNI, DHI) values using cloud cover data and the
|
||||||
|
`pvlib` library.
|
||||||
|
|
||||||
5. **Store Data**:
|
5. **Store Data**:
|
||||||
- Combines all hourly data into `WeatherDataRecord` objects, with keys
|
- Combines all hourly data into `WeatherDataRecord` objects, with keys
|
||||||
standardized according to `WeatherDataRecord` attributes.
|
standardized according to `WeatherDataRecord` attributes.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Get ClearOutside web content - either from site or cached
|
# Get ClearOutside web content - either from site or cached
|
||||||
response = self._request_forecast(force_update=force_update) # type: ignore
|
response = self._request_forecast(force_update=force_update) # type: ignore
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
@@ -9,6 +10,9 @@ import pytest
|
|||||||
DIR_PROJECT_ROOT = Path(__file__).parent.parent
|
DIR_PROJECT_ROOT = Path(__file__).parent.parent
|
||||||
DIR_TESTDATA = Path(__file__).parent / "testdata"
|
DIR_TESTDATA = Path(__file__).parent / "testdata"
|
||||||
|
|
||||||
|
DIR_DOCS_GENERATED = DIR_PROJECT_ROOT / "docs" / "_generated"
|
||||||
|
DIR_TEST_GENERATED = DIR_TESTDATA / "docs" / "_generated"
|
||||||
|
|
||||||
|
|
||||||
def test_openapi_spec_current(config_eos):
|
def test_openapi_spec_current(config_eos):
|
||||||
"""Verify the openapi spec hasn´t changed."""
|
"""Verify the openapi spec hasn´t changed."""
|
||||||
@@ -74,11 +78,14 @@ def test_openapi_md_current(config_eos):
|
|||||||
|
|
||||||
def test_config_md_current(config_eos):
|
def test_config_md_current(config_eos):
|
||||||
"""Verify the generated configuration markdown hasn´t changed."""
|
"""Verify the generated configuration markdown hasn´t changed."""
|
||||||
expected_config_md_path = DIR_PROJECT_ROOT / "docs" / "_generated" / "config.md"
|
assert DIR_DOCS_GENERATED.exists()
|
||||||
new_config_md_path = DIR_TESTDATA / "config-new.md"
|
|
||||||
|
|
||||||
with expected_config_md_path.open("r", encoding="utf-8", newline=None) as f_expected:
|
# Remove any leftover files from last run
|
||||||
expected_config_md = f_expected.read()
|
if DIR_TEST_GENERATED.exists():
|
||||||
|
shutil.rmtree(DIR_TEST_GENERATED)
|
||||||
|
|
||||||
|
# Ensure test dir exists
|
||||||
|
DIR_TEST_GENERATED.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
# Patch get_config and import within guard to patch global variables within the eos module.
|
# Patch get_config and import within guard to patch global variables within the eos module.
|
||||||
with patch("akkudoktoreos.config.config.get_config", return_value=config_eos):
|
with patch("akkudoktoreos.config.config.get_config", return_value=config_eos):
|
||||||
@@ -87,17 +94,33 @@ def test_config_md_current(config_eos):
|
|||||||
sys.path.insert(0, str(root_dir))
|
sys.path.insert(0, str(root_dir))
|
||||||
from scripts import generate_config_md
|
from scripts import generate_config_md
|
||||||
|
|
||||||
config_md = generate_config_md.generate_config_md(config_eos)
|
# Get all the top level fields
|
||||||
|
field_names = sorted(config_eos.__class__.model_fields.keys())
|
||||||
|
|
||||||
if os.name == "nt":
|
# Create the file paths
|
||||||
config_md = config_md.replace("\\\\", "/")
|
expected = [ DIR_DOCS_GENERATED / "config.md", DIR_DOCS_GENERATED / "configexample.md", ]
|
||||||
with new_config_md_path.open("w", encoding="utf-8", newline="\n") as f_new:
|
tested = [ DIR_TEST_GENERATED / "config.md", DIR_TEST_GENERATED / "configexample.md", ]
|
||||||
f_new.write(config_md)
|
for field_name in field_names:
|
||||||
|
file_name = f"config{field_name.lower()}.md"
|
||||||
|
expected.append(DIR_DOCS_GENERATED / file_name)
|
||||||
|
tested.append(DIR_TEST_GENERATED / file_name)
|
||||||
|
|
||||||
|
# Create test files
|
||||||
|
config_md = generate_config_md.generate_config_md(tested[0], config_eos)
|
||||||
|
|
||||||
|
# Check test files are the same as the expected files
|
||||||
|
for i, expected_path in enumerate(expected):
|
||||||
|
tested_path = tested[i]
|
||||||
|
|
||||||
|
with expected_path.open("r", encoding="utf-8", newline=None) as f_expected:
|
||||||
|
expected_config_md = f_expected.read()
|
||||||
|
with tested_path.open("r", encoding="utf-8", newline=None) as f_expected:
|
||||||
|
tested_config_md = f_expected.read()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
assert config_md == expected_config_md
|
assert tested_config_md == expected_config_md
|
||||||
except AssertionError as e:
|
except AssertionError as e:
|
||||||
pytest.fail(
|
pytest.fail(
|
||||||
f"Expected {new_config_md_path} to equal {expected_config_md_path}.\n"
|
f"Expected {tested_path} to equal {expected_path}.\n"
|
||||||
+ f"If ok: `make gen-docs` or `cp {new_config_md_path} {expected_config_md_path}`\n"
|
+ f"If ok: `make gen-docs` or `cp {tested_path} {expected_path}`\n"
|
||||||
)
|
)
|
||||||
|
|||||||
178
tests/test_docsphinx.py
Normal file
178
tests/test_docsphinx.py
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
from fnmatch import fnmatch
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
DIR_PROJECT_ROOT = Path(__file__).absolute().parent.parent
|
||||||
|
DIR_BUILD = DIR_PROJECT_ROOT / "build"
|
||||||
|
DIR_BUILD_DOCS = DIR_PROJECT_ROOT / "build" / "docs"
|
||||||
|
DIR_DOCS = DIR_PROJECT_ROOT / "docs"
|
||||||
|
DIR_SRC = DIR_PROJECT_ROOT / "src"
|
||||||
|
|
||||||
|
HASH_FILE = DIR_BUILD / ".sphinx_hash.json"
|
||||||
|
|
||||||
|
# Allowed file suffixes to consider
|
||||||
|
ALLOWED_SUFFIXES = {".py", ".md", ".json"}
|
||||||
|
|
||||||
|
# Directory patterns to exclude (glob-like)
|
||||||
|
EXCLUDED_DIR_PATTERNS = {"*_autosum", "*__pycache__"}
|
||||||
|
|
||||||
|
|
||||||
|
def is_excluded_dir(path: Path) -> bool:
|
||||||
|
"""Check whether a directory should be excluded based on name patterns."""
|
||||||
|
return any(fnmatch(path.name, pattern) for pattern in EXCLUDED_DIR_PATTERNS)
|
||||||
|
|
||||||
|
|
||||||
|
def hash_tree(paths: list[Path], suffixes=ALLOWED_SUFFIXES) -> str:
|
||||||
|
"""Return SHA256 hash for files under `paths`.
|
||||||
|
|
||||||
|
Restricted by suffix, excluding excluded directory patterns.
|
||||||
|
"""
|
||||||
|
h = hashlib.sha256()
|
||||||
|
|
||||||
|
for root in paths:
|
||||||
|
if not root.exists():
|
||||||
|
continue
|
||||||
|
for p in sorted(root.rglob("*")):
|
||||||
|
# Skip excluded directories
|
||||||
|
if p.is_dir() and is_excluded_dir(p):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Skip files inside excluded directories
|
||||||
|
if any(is_excluded_dir(parent) for parent in p.parents):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Hash only allowed file types
|
||||||
|
if p.is_file() and p.suffix.lower() in suffixes:
|
||||||
|
h.update(p.read_bytes())
|
||||||
|
|
||||||
|
return h.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def find_sphinx_build() -> str:
|
||||||
|
venv = os.getenv("VIRTUAL_ENV")
|
||||||
|
paths = [Path(venv)] if venv else []
|
||||||
|
paths.append(DIR_PROJECT_ROOT / ".venv")
|
||||||
|
|
||||||
|
for base in paths:
|
||||||
|
cmd = base / ("Scripts" if os.name == "nt" else "bin") / ("sphinx-build.exe" if os.name == "nt" else "sphinx-build")
|
||||||
|
if cmd.exists():
|
||||||
|
return str(cmd)
|
||||||
|
return "sphinx-build"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def sphinx_changed() -> bool:
|
||||||
|
"""Returns True if any watched files have changed since last run.
|
||||||
|
|
||||||
|
Hash is stored in .sphinx_hash.json.
|
||||||
|
"""
|
||||||
|
# Directories whose changes should trigger rebuilding docs
|
||||||
|
watched_paths = [Path("docs"), Path("src")]
|
||||||
|
|
||||||
|
current_hash = hash_tree(watched_paths)
|
||||||
|
|
||||||
|
# Load previous hash
|
||||||
|
try:
|
||||||
|
previous = json.loads(HASH_FILE.read_text())
|
||||||
|
previous_hash = previous.get("hash")
|
||||||
|
except Exception:
|
||||||
|
previous_hash = None
|
||||||
|
|
||||||
|
changed = (previous_hash != current_hash)
|
||||||
|
|
||||||
|
# Update stored hash
|
||||||
|
HASH_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
HASH_FILE.write_text(json.dumps({"hash": current_hash}, indent=2))
|
||||||
|
|
||||||
|
return changed
|
||||||
|
|
||||||
|
|
||||||
|
class TestSphinxDocumentation:
|
||||||
|
"""Test class to verify Sphinx documentation generation.
|
||||||
|
|
||||||
|
Ensures no major warnings are emitted.
|
||||||
|
"""
|
||||||
|
|
||||||
|
SPHINX_CMD = [
|
||||||
|
find_sphinx_build(),
|
||||||
|
"-M",
|
||||||
|
"html",
|
||||||
|
str(DIR_DOCS),
|
||||||
|
str(DIR_BUILD_DOCS),
|
||||||
|
]
|
||||||
|
|
||||||
|
def _cleanup_autosum_dirs(self):
|
||||||
|
"""Delete all *_autosum folders inside docs/."""
|
||||||
|
for folder in DIR_DOCS.rglob("*_autosum"):
|
||||||
|
if folder.is_dir():
|
||||||
|
shutil.rmtree(folder)
|
||||||
|
|
||||||
|
def _cleanup_build_dir(self):
|
||||||
|
"""Delete build/docs directory if present."""
|
||||||
|
if DIR_BUILD_DOCS.exists():
|
||||||
|
shutil.rmtree(DIR_BUILD_DOCS)
|
||||||
|
|
||||||
|
def test_sphinx_build(self, sphinx_changed: bool, is_full_run: bool):
|
||||||
|
"""Build Sphinx documentation and ensure no major warnings appear in the build output."""
|
||||||
|
if not is_full_run:
|
||||||
|
pytest.skip("Skipping Sphinx test — not full run")
|
||||||
|
|
||||||
|
if not sphinx_changed:
|
||||||
|
pytest.skip(f"Skipping Sphinx build — no relevant file changes detected: {HASH_FILE}")
|
||||||
|
|
||||||
|
# Ensure docs folder exists
|
||||||
|
if not Path("docs").exists():
|
||||||
|
pytest.skip(f"Skipping Sphinx build test - docs folder not present: {DIR_DOCS}")
|
||||||
|
|
||||||
|
# Clean directories
|
||||||
|
self._cleanup_autosum_dirs()
|
||||||
|
self._cleanup_build_dir()
|
||||||
|
|
||||||
|
# Set environment for sphinx run (sphinx will make eos create a config file)
|
||||||
|
eos_tmp_dir = tempfile.TemporaryDirectory()
|
||||||
|
eos_dir = str(eos_tmp_dir.name)
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["EOS_DIR"] = eos_dir
|
||||||
|
env["EOS_CONFIG_DIR"] = eos_dir
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Run sphinx-build
|
||||||
|
project_dir = Path(__file__).parent.parent
|
||||||
|
process = subprocess.run(
|
||||||
|
self.SPHINX_CMD,
|
||||||
|
check=True,
|
||||||
|
env=env,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
text=True,
|
||||||
|
cwd=project_dir,
|
||||||
|
)
|
||||||
|
# Combine output
|
||||||
|
output = process.stdout + "\n" + process.stderr
|
||||||
|
returncode = process.returncode
|
||||||
|
except:
|
||||||
|
output = f"ERROR: Could not start sphinx-build - {self.SPHINX_CMD}"
|
||||||
|
returncode = -1
|
||||||
|
|
||||||
|
# Remove temporary EOS_DIR
|
||||||
|
eos_tmp_dir.cleanup()
|
||||||
|
|
||||||
|
assert returncode == 0
|
||||||
|
|
||||||
|
# Possible markers: ERROR: WARNING: TRACEBACK:
|
||||||
|
major_markers = ("ERROR:", "TRACEBACK:")
|
||||||
|
|
||||||
|
bad_lines = [
|
||||||
|
line for line in output.splitlines()
|
||||||
|
if any(marker in line for marker in major_markers)
|
||||||
|
]
|
||||||
|
|
||||||
|
assert not bad_lines, f"Sphinx build contained errors:\n" + "\n".join(bad_lines)
|
||||||
371
tests/test_docstringrst.py
Normal file
371
tests/test_docstringrst.py
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
import importlib
|
||||||
|
import importlib.util
|
||||||
|
import inspect
|
||||||
|
import pkgutil
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from difflib import SequenceMatcher
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from docutils import nodes
|
||||||
|
from docutils.core import publish_parts
|
||||||
|
from docutils.frontend import OptionParser
|
||||||
|
from docutils.parsers.rst import Directive, Parser, directives
|
||||||
|
from docutils.utils import Reporter, new_document
|
||||||
|
from sphinx.ext.napoleon import Config as NapoleonConfig
|
||||||
|
from sphinx.ext.napoleon.docstring import GoogleDocstring
|
||||||
|
|
||||||
|
DIR_PROJECT_ROOT = Path(__file__).absolute().parent.parent
|
||||||
|
DIR_DOCS = DIR_PROJECT_ROOT / "docs"
|
||||||
|
|
||||||
|
PACKAGE_NAME = "akkudoktoreos"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Location ignore rules (regex)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Locations to ignore (regex). Note the escaped dot for literal '.'
|
||||||
|
IGNORE_LOCATIONS = [
|
||||||
|
r"\.__new__$",
|
||||||
|
|
||||||
|
# Pydantic
|
||||||
|
r"\.model_copy$",
|
||||||
|
r"\.model_dump$",
|
||||||
|
r"\.model_dump_json$",
|
||||||
|
r"\.field_serializer$",
|
||||||
|
r"\.field_validator$",
|
||||||
|
r"\.model_validator$",
|
||||||
|
r"\.computed_field$",
|
||||||
|
r"\.Field$",
|
||||||
|
r"\.FieldInfo.*",
|
||||||
|
r"\.ComputedFieldInfo.*",
|
||||||
|
r"\.PrivateAttr$",
|
||||||
|
|
||||||
|
# pathlib
|
||||||
|
r"\.Path.*",
|
||||||
|
|
||||||
|
# MarkdownIt
|
||||||
|
r"\.MarkdownIt.*",
|
||||||
|
|
||||||
|
# FastAPI
|
||||||
|
r"\.FastAPI.*",
|
||||||
|
r"\.FileResponse.*",
|
||||||
|
r"\.PdfResponse.*",
|
||||||
|
r"\.HTTPException$",
|
||||||
|
|
||||||
|
# bokeh
|
||||||
|
r"\.bokeh.*",
|
||||||
|
r"\.figure.*",
|
||||||
|
r"\.ColumnDataSource.*",
|
||||||
|
r"\.LinearAxis.*",
|
||||||
|
r"\.Range1d.*",
|
||||||
|
|
||||||
|
# BeautifulSoup
|
||||||
|
r"\.BeautifulSoup.*",
|
||||||
|
|
||||||
|
# ExponentialSmoothing
|
||||||
|
r"\.ExponentialSmoothing.*",
|
||||||
|
|
||||||
|
# Pendulum
|
||||||
|
r"\.Date$",
|
||||||
|
r"\.DateTime$",
|
||||||
|
r"\.Duration$",
|
||||||
|
|
||||||
|
# ABC
|
||||||
|
r"\.abstractmethod$",
|
||||||
|
|
||||||
|
# numpytypes
|
||||||
|
r"\.NDArray$",
|
||||||
|
|
||||||
|
# typing
|
||||||
|
r"\.ParamSpec",
|
||||||
|
r"\.TypeVar",
|
||||||
|
r"\.Annotated",
|
||||||
|
|
||||||
|
# contextlib
|
||||||
|
r"\.asynccontextmanager$",
|
||||||
|
|
||||||
|
# concurrent
|
||||||
|
r"\.ThreadPoolExecutor.*",
|
||||||
|
|
||||||
|
# asyncio
|
||||||
|
r"\.Lock.*",
|
||||||
|
|
||||||
|
# scipy
|
||||||
|
r"\.RegularGridInterpolator.*",
|
||||||
|
|
||||||
|
# pylogging
|
||||||
|
r"\.InterceptHandler.filter$",
|
||||||
|
|
||||||
|
# itertools
|
||||||
|
r"\.chain$",
|
||||||
|
|
||||||
|
# functools
|
||||||
|
r"\.partial$",
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Error message ignore rules by location (regex)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
IGNORE_ERRORS_BY_LOCATION = {
|
||||||
|
r"^akkudoktoreos.*": [
|
||||||
|
r"Unexpected possible title overline or transition.*",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# --- Use your global paths ---
|
||||||
|
conf_path = DIR_DOCS / "conf.py"
|
||||||
|
|
||||||
|
spec = importlib.util.spec_from_file_location("sphinx_conf", conf_path)
|
||||||
|
if spec is None:
|
||||||
|
raise AssertionError(f"Can not import sphinx_conf from {conf_path}")
|
||||||
|
sphinx_conf = importlib.util.module_from_spec(spec)
|
||||||
|
sys.modules["sphinx_conf"] = sphinx_conf
|
||||||
|
if spec.loader is None:
|
||||||
|
raise AssertionError(f"Can not import sphinx_conf from {conf_path}")
|
||||||
|
spec.loader.exec_module(sphinx_conf)
|
||||||
|
|
||||||
|
# Build NapoleonConfig with all options
|
||||||
|
napoleon_config = NapoleonConfig(
|
||||||
|
napoleon_google_docstring=getattr(sphinx_conf, "napoleon_google_docstring", True),
|
||||||
|
napoleon_numpy_docstring=getattr(sphinx_conf, "napoleon_numpy_docstring", False),
|
||||||
|
napoleon_include_init_with_doc=getattr(sphinx_conf, "napoleon_include_init_with_doc", False),
|
||||||
|
napoleon_include_private_with_doc=getattr(sphinx_conf, "napoleon_include_private_with_doc", False),
|
||||||
|
napoleon_include_special_with_doc=getattr(sphinx_conf, "napoleon_include_special_with_doc", True),
|
||||||
|
napoleon_use_admonition_for_examples=getattr(sphinx_conf, "napoleon_use_admonition_for_examples", False),
|
||||||
|
napoleon_use_admonition_for_notes=getattr(sphinx_conf, "napoleon_use_admonition_for_notes", False),
|
||||||
|
napoleon_use_admonition_for_references=getattr(sphinx_conf, "napoleon_use_admonition_for_references", False),
|
||||||
|
napoleon_use_ivar=getattr(sphinx_conf, "napoleon_use_ivar", False),
|
||||||
|
napoleon_use_param=getattr(sphinx_conf, "napoleon_use_param", True),
|
||||||
|
napoleon_use_rtype=getattr(sphinx_conf, "napoleon_use_rtype", True),
|
||||||
|
napoleon_preprocess_types=getattr(sphinx_conf, "napoleon_preprocess_types", False),
|
||||||
|
napoleon_type_aliases=getattr(sphinx_conf, "napoleon_type_aliases", None),
|
||||||
|
napoleon_attr_annotations=getattr(sphinx_conf, "napoleon_attr_annotations", True),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
FENCE_RE = re.compile(r"^```(\w*)\s*$")
|
||||||
|
|
||||||
|
|
||||||
|
def replace_fenced_code_blocks(doc: str) -> tuple[str, bool]:
|
||||||
|
"""Replace fenced code blocks (```lang) in a docstring with RST code-block syntax.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(new_doc, changed):
|
||||||
|
new_doc: The docstring with replacements applied
|
||||||
|
changed: True if any fenced block was replaced
|
||||||
|
"""
|
||||||
|
out_lines = []
|
||||||
|
inside = False
|
||||||
|
lang = ""
|
||||||
|
buffer: list[str] = []
|
||||||
|
changed = False
|
||||||
|
|
||||||
|
lines = doc.split("\n")
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
stripped = line.strip()
|
||||||
|
|
||||||
|
# Detect opening fence: ``` or ```python
|
||||||
|
m = FENCE_RE.match(stripped)
|
||||||
|
if m and not inside:
|
||||||
|
inside = True
|
||||||
|
lang = m.group(1) or ""
|
||||||
|
# Write RST code-block header
|
||||||
|
if lang:
|
||||||
|
out_lines.append(f" .. code-block:: {lang}")
|
||||||
|
else:
|
||||||
|
out_lines.append(" .. code-block::")
|
||||||
|
out_lines.append("") # blank line required by RST
|
||||||
|
changed = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Detect closing fence ```
|
||||||
|
if stripped == "```" and inside:
|
||||||
|
# Emit fenced code content with indentation
|
||||||
|
for b in buffer:
|
||||||
|
out_lines.append(" " + b)
|
||||||
|
out_lines.append("") # trailing blank line to close environment
|
||||||
|
inside = False
|
||||||
|
buffer = []
|
||||||
|
continue
|
||||||
|
|
||||||
|
if inside:
|
||||||
|
buffer.append(line)
|
||||||
|
else:
|
||||||
|
out_lines.append(line)
|
||||||
|
|
||||||
|
# If doc ended while still in fenced code, flush
|
||||||
|
if inside:
|
||||||
|
changed = True
|
||||||
|
for b in buffer:
|
||||||
|
out_lines.append(" " + b)
|
||||||
|
out_lines.append("")
|
||||||
|
inside = False
|
||||||
|
|
||||||
|
return "\n".join(out_lines), changed
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_docutils_for_sphinx():
|
||||||
|
|
||||||
|
class NoOpDirective(Directive):
|
||||||
|
has_content = True
|
||||||
|
required_arguments = 0
|
||||||
|
optional_arguments = 100
|
||||||
|
final_argument_whitespace = True
|
||||||
|
def run(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
for d in ["attribute", "data", "method", "function", "class", "event", "todo"]:
|
||||||
|
directives.register_directive(d, NoOpDirective)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_rst(text: str) -> list[tuple[int, str]]:
|
||||||
|
"""Validate a string as reStructuredText.
|
||||||
|
|
||||||
|
Returns a list of tuples: (line_number, message).
|
||||||
|
"""
|
||||||
|
if not text or not text.strip():
|
||||||
|
return []
|
||||||
|
|
||||||
|
warnings: list[tuple[int, str]] = []
|
||||||
|
|
||||||
|
class RecordingReporter(Reporter):
|
||||||
|
"""Capture warnings/errors instead of halting."""
|
||||||
|
def system_message(self, level, message, *children, **kwargs):
|
||||||
|
line = kwargs.get("line", None)
|
||||||
|
warnings.append((line or 0, message))
|
||||||
|
return nodes.system_message(message, level=level, type=self.levels[level], *children, **kwargs)
|
||||||
|
|
||||||
|
# Create default settings
|
||||||
|
settings = OptionParser(components=(Parser,)).get_default_values()
|
||||||
|
|
||||||
|
document = new_document("<docstring>", settings=settings)
|
||||||
|
|
||||||
|
# Attach custom reporter
|
||||||
|
document.reporter = RecordingReporter(
|
||||||
|
source="<docstring>",
|
||||||
|
report_level=1, # capture warnings and above
|
||||||
|
halt_level=100, # never halt
|
||||||
|
stream=None,
|
||||||
|
debug=False
|
||||||
|
)
|
||||||
|
|
||||||
|
parser = Parser()
|
||||||
|
parser.parse(text, document)
|
||||||
|
|
||||||
|
return warnings
|
||||||
|
|
||||||
|
|
||||||
|
def iter_docstrings(package_name: str):
|
||||||
|
"""Yield docstrings of modules, classes, functions in the given package."""
|
||||||
|
|
||||||
|
package = importlib.import_module(package_name)
|
||||||
|
|
||||||
|
for module_info in pkgutil.walk_packages(package.__path__, package.__name__ + "."):
|
||||||
|
module = importlib.import_module(module_info.name)
|
||||||
|
|
||||||
|
# Module docstring
|
||||||
|
if module.__doc__:
|
||||||
|
yield f"Module {module.__name__}", inspect.getdoc(module)
|
||||||
|
|
||||||
|
# Classes + methods
|
||||||
|
for _, obj in inspect.getmembers(module):
|
||||||
|
if inspect.isclass(obj) or inspect.isfunction(obj):
|
||||||
|
if obj.__doc__:
|
||||||
|
yield f"{module.__name__}.{obj.__name__}", inspect.getdoc(obj)
|
||||||
|
|
||||||
|
# Methods of classes
|
||||||
|
if inspect.isclass(obj):
|
||||||
|
for _, meth in inspect.getmembers(obj, inspect.isfunction):
|
||||||
|
if meth.__doc__:
|
||||||
|
yield f"{module.__name__}.{obj.__name__}.{meth.__name__}", inspect.getdoc(meth)
|
||||||
|
|
||||||
|
|
||||||
|
def map_converted_to_original(orig: str, conv: str) -> dict[int,int]:
|
||||||
|
"""Map original docstring line to converted docstring line.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
mapping: key = converted line index (0-based), value = original line index (0-based).
|
||||||
|
"""
|
||||||
|
orig_lines = orig.splitlines()
|
||||||
|
conv_lines = conv.splitlines()
|
||||||
|
|
||||||
|
matcher = SequenceMatcher(None, orig_lines, conv_lines)
|
||||||
|
line_map = {}
|
||||||
|
for tag, i1, i2, j1, j2 in matcher.get_opcodes():
|
||||||
|
if tag in ("equal", "replace"):
|
||||||
|
for o, c in zip(range(i1, i2), range(j1, j2)):
|
||||||
|
line_map[c] = o
|
||||||
|
elif tag == "insert":
|
||||||
|
for c in range(j1, j2):
|
||||||
|
line_map[c] = max(i1 - 1, 0)
|
||||||
|
return line_map
|
||||||
|
|
||||||
|
|
||||||
|
def test_all_docstrings_rst_compliant():
|
||||||
|
"""All docstrings must be valid reStructuredText."""
|
||||||
|
failures = []
|
||||||
|
|
||||||
|
for location, doc in iter_docstrings(PACKAGE_NAME):
|
||||||
|
# Skip ignored locations
|
||||||
|
if any(re.search(pat, location) for pat in IGNORE_LOCATIONS):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# convert like sphinx napoleon does
|
||||||
|
doc_converted = str(GoogleDocstring(doc, napoleon_config))
|
||||||
|
|
||||||
|
# Register directives that sphinx knows - just to avaid errors
|
||||||
|
prepare_docutils_for_sphinx()
|
||||||
|
|
||||||
|
# Validate
|
||||||
|
messages = validate_rst(doc_converted)
|
||||||
|
if not messages:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Map converted line numbers back to original docstring
|
||||||
|
line_map = map_converted_to_original(doc, doc_converted)
|
||||||
|
|
||||||
|
# Filter messages
|
||||||
|
filtered_messages = []
|
||||||
|
ignore_msg_patterns = []
|
||||||
|
for loc_pattern, patterns in IGNORE_ERRORS_BY_LOCATION.items():
|
||||||
|
if re.search(loc_pattern, location):
|
||||||
|
ignore_msg_patterns.extend(patterns)
|
||||||
|
|
||||||
|
for conv_line, msg_text in messages:
|
||||||
|
orig_line = line_map.get(conv_line - 1, conv_line - 1) + 1
|
||||||
|
if any(re.search(pat, msg_text) for pat in ignore_msg_patterns):
|
||||||
|
continue
|
||||||
|
filtered_messages.append((orig_line, msg_text))
|
||||||
|
|
||||||
|
if filtered_messages:
|
||||||
|
failures.append((location, filtered_messages, doc, doc_converted))
|
||||||
|
|
||||||
|
# Raise AssertionError with nicely formatted output
|
||||||
|
if failures:
|
||||||
|
msg = "Invalid reST docstrings (see https://www.sphinx-doc.org/en/master/usage/extensions/example_google.html for valid format):\n"
|
||||||
|
for location, errors, doc, doc_converted in failures:
|
||||||
|
msg += f"\n--- {location} ---\n"
|
||||||
|
msg += "\nConverted by Sphinx Napoleon:\n"
|
||||||
|
doc_lines = doc_converted.splitlines()
|
||||||
|
for i, line_content in enumerate(doc_lines, start=1):
|
||||||
|
line_str = f"{i:2}" # fixed-width
|
||||||
|
msg += f" L{line_str}: {line_content}\n"
|
||||||
|
msg += "\nOriginal:\n"
|
||||||
|
doc_lines = doc.splitlines()
|
||||||
|
error_map = {line: err for line, err in errors}
|
||||||
|
for i, line_content in enumerate(doc_lines, start=1):
|
||||||
|
line_str = f"{i:2}" # fixed-width
|
||||||
|
if i in error_map:
|
||||||
|
msg += f">>> L{line_str}: {line_content} <-- {error_map[i]}\n"
|
||||||
|
else:
|
||||||
|
msg += f" L{line_str}: {line_content}\n"
|
||||||
|
doc_fixed, changed = replace_fenced_code_blocks(doc)
|
||||||
|
if changed:
|
||||||
|
msg += "\nImproved for fenced code blocks:\n"
|
||||||
|
msg += '"""' + doc_fixed + '\n"""\n'
|
||||||
|
msg += f"Total: {len(failures)} docstrings"
|
||||||
|
|
||||||
|
raise AssertionError(msg)
|
||||||
Reference in New Issue
Block a user