mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2025-06-27 16:36:53 +00:00
Add documentation. (#321)
Add documentation that covers: - Prediction - Measuremnt - REST API Add Python scripts that support automatic documentation generation using the Sphinx sphinxcontrib.eval extension. Add automatic update/ test for REST API documentation. Filter proxy endpoints from REST API documentation. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
This commit is contained in:
parent
4cb6dc7270
commit
1866055478
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,8 +1,6 @@
|
|||||||
cache/
|
cache/
|
||||||
output/
|
output/
|
||||||
EOS.config.json
|
EOS.config.json
|
||||||
docs/develop/CONTRIBUTING.md
|
|
||||||
docs/develop/getting_started.md
|
|
||||||
|
|
||||||
# Default ignore folders and files for VS Code, Python
|
# Default ignore folders and files for VS Code, Python
|
||||||
|
|
||||||
@ -258,5 +256,6 @@ visualize_output_*.pdf
|
|||||||
*_pdf.png
|
*_pdf.png
|
||||||
|
|
||||||
# Test files
|
# Test files
|
||||||
openapi-new.json
|
|
||||||
tests/testdata/new_optimize_result*
|
tests/testdata/new_optimize_result*
|
||||||
|
tests/testdata/openapi-new.json
|
||||||
|
tests/testdata/openapi-new.md
|
||||||
|
21
Makefile
21
Makefile
@ -17,6 +17,7 @@ help:
|
|||||||
@echo " docker-build - Rebuild docker image"
|
@echo " docker-build - Rebuild docker image"
|
||||||
@echo " docs - Generate HTML documentation (in build/docs/html/)."
|
@echo " docs - Generate HTML documentation (in build/docs/html/)."
|
||||||
@echo " read-docs - Read HTML documentation in your browser."
|
@echo " read-docs - Read HTML documentation in your browser."
|
||||||
|
@echo " clean-docs - Remove generated documentation.""
|
||||||
@echo " run - Run FastAPI production server in the virtual environment."
|
@echo " run - Run FastAPI production server in the virtual environment."
|
||||||
@echo " run-dev - Run FastAPI development server in the virtual environment (automatically reloads)."
|
@echo " run-dev - Run FastAPI development server in the virtual environment (automatically reloads)."
|
||||||
@echo " dist - Create distribution (in dist/)."
|
@echo " dist - Create distribution (in dist/)."
|
||||||
@ -52,13 +53,6 @@ dist: pip
|
|||||||
|
|
||||||
# Target to generate HTML documentation
|
# Target to generate HTML documentation
|
||||||
docs: pip-dev
|
docs: pip-dev
|
||||||
mkdir -p docs/develop
|
|
||||||
cp README.md docs/develop/getting_started.md
|
|
||||||
# remove top level header and coresponding description
|
|
||||||
sed -i '/^##[^#]/,$$!d' docs/develop/getting_started.md
|
|
||||||
sed -i "1i\# Getting Started\n" docs/develop/getting_started.md
|
|
||||||
cp CONTRIBUTING.md docs/develop
|
|
||||||
sed -i "s/README.md/getting_started.md/g" docs/develop/CONTRIBUTING.md
|
|
||||||
.venv/bin/sphinx-build -M html docs build/docs
|
.venv/bin/sphinx-build -M html docs build/docs
|
||||||
@echo "Documentation generated to build/docs/html/."
|
@echo "Documentation generated to build/docs/html/."
|
||||||
|
|
||||||
@ -67,12 +61,17 @@ read-docs: docs
|
|||||||
@echo "Read the documentation in your browser"
|
@echo "Read the documentation in your browser"
|
||||||
.venv/bin/python -m webbrowser build/docs/html/index.html
|
.venv/bin/python -m webbrowser build/docs/html/index.html
|
||||||
|
|
||||||
# Clean target to remove generated documentation, distribution and virtual environment
|
# Clean target to remove generated documentation and documentation artefacts
|
||||||
clean:
|
clean-docs:
|
||||||
@echo "Cleaning virtual env, distribution and build directories"
|
|
||||||
rm -rf dist build .venv
|
|
||||||
@echo "Searching and deleting all '_autosum' directories in docs..."
|
@echo "Searching and deleting all '_autosum' directories in docs..."
|
||||||
@find docs -type d -name '_autosummary' -exec rm -rf {} +;
|
@find docs -type d -name '_autosummary' -exec rm -rf {} +;
|
||||||
|
@echo "Cleaning docs build directories"
|
||||||
|
rm -rf build/docs
|
||||||
|
|
||||||
|
# Clean target to remove generated documentation, distribution and virtual environment
|
||||||
|
clean: clean-docs
|
||||||
|
@echo "Cleaning virtual env, distribution and build directories"
|
||||||
|
rm -rf build .venv
|
||||||
@echo "Deletion complete."
|
@echo "Deletion complete."
|
||||||
|
|
||||||
run:
|
run:
|
||||||
|
@ -93,7 +93,7 @@ Each class is designed to be easily customized and extended to integrate additio
|
|||||||
|
|
||||||
## Server API
|
## Server API
|
||||||
|
|
||||||
See the Swagger API documentation for detailed information: [EOS OpenAPI Spec](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/docs/akkudoktoreos/openapi.json)
|
See the Swagger API documentation for detailed information: [EOS OpenAPI Spec](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json)
|
||||||
|
|
||||||
## Further resources
|
## Further resources
|
||||||
|
|
||||||
|
93
docs/akkudoktoreos/measurement.md
Normal file
93
docs/akkudoktoreos/measurement.md
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
% SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# Measurements
|
||||||
|
|
||||||
|
Measurements are utilized to refine predictions using real data from your system, thereby enhancing
|
||||||
|
accuracy.
|
||||||
|
|
||||||
|
- **Household Load Measurement**
|
||||||
|
- **Grid Export Measurement**
|
||||||
|
- **Grid Import Measurement**
|
||||||
|
|
||||||
|
## Storing Measurements
|
||||||
|
|
||||||
|
EOS stores measurements in a **key-value store**, where the term `measurement key` refers to the
|
||||||
|
unique identifier used to store and retrieve specific measurement data. Note that the key-value
|
||||||
|
store is memory-based, meaning that all stored data will be lost upon restarting the EOS REST
|
||||||
|
server.
|
||||||
|
|
||||||
|
:::{admonition} Todo
|
||||||
|
:class: note
|
||||||
|
Ensure that measurement data persists across server restarts.
|
||||||
|
:::
|
||||||
|
|
||||||
|
Several endpoints of the EOS REST server allow for the management and retrieval of these
|
||||||
|
measurements.
|
||||||
|
|
||||||
|
The measurement data must be or is provided in one of the following formats:
|
||||||
|
|
||||||
|
### 1. DateTimeData
|
||||||
|
|
||||||
|
A dictionary with the following structure:
|
||||||
|
|
||||||
|
```JSON
|
||||||
|
{
|
||||||
|
"start_datetime": "2024-01-01 00:00:00",
|
||||||
|
"interval": "1 Hour",
|
||||||
|
"<measurement key>": [value, value, ...],
|
||||||
|
"<measurement key>": [value, value, ...],
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. DateTimeDataFrame
|
||||||
|
|
||||||
|
A JSON string created from a [pandas](https://pandas.pydata.org/docs/index.html) dataframe with a
|
||||||
|
`DatetimeIndex`. Use [pandas.DataFrame.to_json(orient="index")](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_json.html#pandas.DataFrame.to_json).
|
||||||
|
The column name of the data must be the same as the names of the `measurement key`s.
|
||||||
|
|
||||||
|
### 3. DateTimeSeries
|
||||||
|
|
||||||
|
A JSON string created from a [pandas](https://pandas.pydata.org/docs/index.html) series with a
|
||||||
|
`DatetimeIndex`. Use [pandas.Series.to_json(orient="index")](https://pandas.pydata.org/docs/reference/api/pandas.Series.to_json.html#pandas.Series.to_json).
|
||||||
|
|
||||||
|
## Load Measurement
|
||||||
|
|
||||||
|
The EOS measurement store provides for storing meter readings of loads. There are currently five loads
|
||||||
|
foreseen. The associated `measurement key`s are:
|
||||||
|
|
||||||
|
- `measurement_load0_mr`: Load0 meter reading [kWh]
|
||||||
|
- `measurement_load1_mr`: Load1 meter reading [kWh]
|
||||||
|
- `measurement_load2_mr`: Load2 meter reading [kWh]
|
||||||
|
- `measurement_load3_mr`: Load3 meter reading [kWh]
|
||||||
|
- `measurement_load4_mr`: Load4 meter reading [kWh]
|
||||||
|
|
||||||
|
For ease of use, you can assign descriptive names to the `measurement key`s to represent your
|
||||||
|
system's load sources. Use the following `configuration options` to set these names
|
||||||
|
(e.g., 'Dish Washer', 'Heat Pump'):
|
||||||
|
|
||||||
|
- `measurement_load0_name`: Name of the load0 source
|
||||||
|
- `measurement_load1_name`: Name of the load1 source
|
||||||
|
- `measurement_load2_name`: Name of the load2 source
|
||||||
|
- `measurement_load3_name`: Name of the load3 source
|
||||||
|
- `measurement_load4_name`: Name of the load4 source
|
||||||
|
|
||||||
|
Load measurements can be stored for any datetime. The values between different meter readings are
|
||||||
|
linearly approximated. Since optimization occurs on the hour, storing values between hours is
|
||||||
|
generally not useful.
|
||||||
|
|
||||||
|
The EOS measurement store automatically sums all given loads to create a total load value series
|
||||||
|
for specified intervals, usually one hour. This aggregated data can be used for load predictions.
|
||||||
|
|
||||||
|
## Grid Export/ Import Measurement
|
||||||
|
|
||||||
|
The EOS measurement store also allows for the storage of meter readings for grid import and export.
|
||||||
|
The associated `measurement key`s are:
|
||||||
|
|
||||||
|
- `measurement_grid_export_mr`: Export to grid meter reading [kWh]
|
||||||
|
- `measurement_grid_import_mr`: Import from grid meter reading [kWh]
|
||||||
|
|
||||||
|
:::{admonition} Todo
|
||||||
|
:class: note
|
||||||
|
Currently not used. Integrate grid meter readings into the respective predictions.
|
||||||
|
:::
|
File diff suppressed because it is too large
Load Diff
401
docs/akkudoktoreos/prediction.md
Normal file
401
docs/akkudoktoreos/prediction.md
Normal file
@ -0,0 +1,401 @@
|
|||||||
|
% SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# Predictions
|
||||||
|
|
||||||
|
Predictions, along with simulations and measurements, form the foundation upon which energy
|
||||||
|
optimization is executed. In EOS, a standard set of predictions is managed, including:
|
||||||
|
|
||||||
|
- **Household Load Prediction**
|
||||||
|
- **Electricity Price Prediction**
|
||||||
|
- **PV Power Prediction**
|
||||||
|
- **Weather Prediction**
|
||||||
|
|
||||||
|
## Storing Predictions
|
||||||
|
|
||||||
|
EOS stores predictions in a **key-value store**, where the term `prediction key` refers to the
|
||||||
|
unique key used to retrieve specific prediction data. The key-value store is in memory. Stored
|
||||||
|
data is lost on re-start of the EOS REST server.
|
||||||
|
|
||||||
|
## Prediction Providers
|
||||||
|
|
||||||
|
Most predictions can be sourced from various providers. The specific provider to use is configured
|
||||||
|
in the EOS configuration. For example:
|
||||||
|
|
||||||
|
```plaintext
|
||||||
|
weather_provider = "ClearOutside"
|
||||||
|
```
|
||||||
|
|
||||||
|
Some providers offer multiple prediction keys. For instance, a weather provider might provide data
|
||||||
|
to prediction keys like:
|
||||||
|
|
||||||
|
- `weather_temp_air` (air temperature)
|
||||||
|
- `weather_wind_speed` (wind speed)
|
||||||
|
|
||||||
|
### Prediction Import Providers
|
||||||
|
|
||||||
|
The prediction import providers are designed to import prediction data from a file or a JSON
|
||||||
|
string. An external entity should update the file or JSON string whenever new prediction data
|
||||||
|
becomes available.
|
||||||
|
|
||||||
|
The prediction data must be provided in one of the following formats:
|
||||||
|
|
||||||
|
#### 1. DateTimeData
|
||||||
|
|
||||||
|
A dictionary with the following structure:
|
||||||
|
|
||||||
|
```JSON
|
||||||
|
{
|
||||||
|
"start_datetime": "2024-01-01 00:00:00",
|
||||||
|
"interval": "1 Hour",
|
||||||
|
"<prediction key>": [value, value, ...],
|
||||||
|
"<prediction key>": [value, value, ...],
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. DateTimeDataFrame
|
||||||
|
|
||||||
|
A JSON string created from a [pandas](https://pandas.pydata.org/docs/index.html) dataframe with a
|
||||||
|
`DatetimeIndex`. Use [pandas.DataFrame.to_json(orient="index")](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_json.html#pandas.DataFrame.to_json).
|
||||||
|
The column name of the data must be the same as the names of the `prediction key`s.
|
||||||
|
|
||||||
|
#### 3. DateTimeSeries
|
||||||
|
|
||||||
|
A JSON string created from a [pandas](https://pandas.pydata.org/docs/index.html) series with a
|
||||||
|
`DatetimeIndex`. Use [pandas.Series.to_json(orient="index")](https://pandas.pydata.org/docs/reference/api/pandas.Series.to_json.html#pandas.Series.to_json).
|
||||||
|
|
||||||
|
## Adjusted Predictions
|
||||||
|
|
||||||
|
Certain prediction keys include an `_adjusted` suffix, such as `load_total_adjusted`. These
|
||||||
|
predictions are adjusted by real data from your system's measurements if given to enhance accuracy.
|
||||||
|
|
||||||
|
For example, the load prediction provider `LoadAkkudoktor` takes generic load data assembled by
|
||||||
|
Akkudoktor.net, maps that to the yearly energy consumption given in the configuration option
|
||||||
|
`loadakkudoktor_year_energy`, and finally adjusts the predicted load by the `measurement_loads`
|
||||||
|
of your system.
|
||||||
|
|
||||||
|
## Prediction Updates
|
||||||
|
|
||||||
|
Predictions are updated at the start of each energy management run, i.e., when EOS performs
|
||||||
|
optimization. Key considerations for updates include:
|
||||||
|
|
||||||
|
- Predictions sourced from online providers are usually rate-limited to one retrieval per hour.
|
||||||
|
- Only predictions with a configured provider are updated.
|
||||||
|
- Some providers may not support all generic prediction keys, leading to potential gaps
|
||||||
|
in updated predictions even after update.
|
||||||
|
|
||||||
|
## Accessing Predictions
|
||||||
|
|
||||||
|
Prediction data can be accessed using the EOS **REST API** via the `/v1/prediction/<...>` endpoints.
|
||||||
|
|
||||||
|
In a standard configuration, the [**REST API**](http://0.0.0.0:8503/docs) of a running EOS instance
|
||||||
|
is available at [http://0.0.0.0:8503/docs](http://0.0.0.0:8503/docs). This link provides access to
|
||||||
|
the API documentation and allows you to explore available endpoints interactively.
|
||||||
|
|
||||||
|
To view all available prediction keys, use the **GET** `/v1/prediction/keys` endpoint.
|
||||||
|
|
||||||
|
If no keys are displayed, or if the ones you need are missing, it indicates that your configuration
|
||||||
|
lacks the necessary prediction provider settings. You can configure prediction providers by using
|
||||||
|
the **PUT** `/v1/config` endpoint. You may save your configuration to the EOS configuration file.
|
||||||
|
|
||||||
|
## Electricity Price Prediction
|
||||||
|
|
||||||
|
Prediction keys:
|
||||||
|
|
||||||
|
- `elecprice_marketprice_wh`: Electricity market price per Wh (€/Wh).
|
||||||
|
- `elecprice_marketprice_kwh`: Electricity market price per kWh (€/kWh).
|
||||||
|
|
||||||
|
Configuration options:
|
||||||
|
|
||||||
|
- `elecprice_provider`: Electricity price provider id of provider to be used.
|
||||||
|
|
||||||
|
- `ElecPriceAkkudoktor`: Retrieves from Akkudoktor.net.
|
||||||
|
- `ElecPriceImport`: Imports from a file or JSON string.
|
||||||
|
|
||||||
|
- `elecprice_charges_kwh`: Electricity price charges (€/kWh).
|
||||||
|
- `elecpriceimport_file_path`: Path to the file to import electricity price forecast data from.
|
||||||
|
- `elecpriceimport_json`: JSON string, dictionary of electricity price forecast value lists.
|
||||||
|
|
||||||
|
### ElecPriceAkkudoktor Provider
|
||||||
|
|
||||||
|
The `ElecPriceAkkudoktor` provider retrieves electricity prices directly from **Akkudoktor.net**,
|
||||||
|
which supplies price data for the next 24 hours. For periods beyond 24 hours, the provider generates
|
||||||
|
prices by extrapolating historical price data combined with the most recent actual prices obtained
|
||||||
|
from Akkudoktor.net. Electricity price charges given in the `elecprice_charges_kwh` configuration
|
||||||
|
option are added.
|
||||||
|
|
||||||
|
### ElecPriceImport Provider
|
||||||
|
|
||||||
|
The `ElecPriceImport` provider is designed to import electricity prices from a file or a JSON
|
||||||
|
string. An external entity should update the file or JSON string whenever new prediction data
|
||||||
|
becomes available.
|
||||||
|
|
||||||
|
The prediction key for the electricity price forecast data is:
|
||||||
|
|
||||||
|
- `elecprice_marketprice_wh`: Electricity market price per Wh (€/Wh).
|
||||||
|
|
||||||
|
The electricity proce forecast data must be provided in one of the formats described in
|
||||||
|
<project:#prediction-import-providers>. The data source must be given in the
|
||||||
|
`elecpriceimport_file_path` or `elecpriceimport_json` configuration option.
|
||||||
|
|
||||||
|
## Load Prediction
|
||||||
|
|
||||||
|
Prediction keys:
|
||||||
|
|
||||||
|
- `load_mean`: Predicted load mean value (W).
|
||||||
|
- `load_std`: Predicted load standard deviation (W).
|
||||||
|
- `load_mean_adjusted`: Predicted load mean value adjusted by load measurement (W).
|
||||||
|
|
||||||
|
Configuration options:
|
||||||
|
|
||||||
|
- `load_provider`: Load provider id of provider to be used.
|
||||||
|
|
||||||
|
- `LoadAkkudoktor`: Retrieves from local database.
|
||||||
|
- `LoadImport`: Imports from a file or JSON string.
|
||||||
|
|
||||||
|
- `loadakkudoktor_year_energy`: Yearly energy consumption (kWh).
|
||||||
|
- `loadimport_file_path`: Path to the file to import load forecast data from.
|
||||||
|
- `loadimport_json`: JSON string, dictionary of load forecast value lists.
|
||||||
|
|
||||||
|
### LoadAkkudoktor Provider
|
||||||
|
|
||||||
|
The `LoadAkkudoktor` provider retrieves generic load data from a local database and tailors it to
|
||||||
|
align with the annual energy consumption specified in the `loadakkudoktor_year_energy` configuration
|
||||||
|
option.
|
||||||
|
|
||||||
|
### LoadImport Provider
|
||||||
|
|
||||||
|
The `LoadImport` provider is designed to import load forecast data from a file or a JSON
|
||||||
|
string. An external entity should update the file or JSON string whenever new prediction data
|
||||||
|
becomes available.
|
||||||
|
|
||||||
|
The prediction keys for the load forecast data are:
|
||||||
|
|
||||||
|
- `load_mean`: Predicted load mean value (W).
|
||||||
|
- `load_std`: Predicted load standard deviation (W).
|
||||||
|
- `load_mean_adjusted`: Predicted load mean value adjusted by load measurement (W).
|
||||||
|
|
||||||
|
The load forecast data must be provided in one of the formats described in
|
||||||
|
<project:#prediction-import-providers>. The data source must be given in the `loadimport_file_path`
|
||||||
|
or `loadimport_json` configuration option.
|
||||||
|
|
||||||
|
## PV Power Prediction
|
||||||
|
|
||||||
|
Prediction keys:
|
||||||
|
|
||||||
|
- `pvforecast_ac_power`: Total DC power (W).
|
||||||
|
- `pvforecast_dc_power`: Total AC power (W).
|
||||||
|
|
||||||
|
Configuration options:
|
||||||
|
|
||||||
|
- `pvforecast_provider`: PVForecast provider id of provider to be used.
|
||||||
|
|
||||||
|
- `PVForecastAkkudoktor`: Retrieves from Akkudoktor.net.
|
||||||
|
- `PVForecastImport`: Imports from a file or JSON string.
|
||||||
|
|
||||||
|
- `latitude`: Latitude in decimal degrees, between -90 and 90, north is positive (ISO 19115) (°)"
|
||||||
|
- `longitude`: Longitude in decimal degrees, within -180 to 180 (°)
|
||||||
|
- `pvforecast<0..5>_surface_tilt`: Tilt angle from horizontal plane. Ignored for two-axis tracking.
|
||||||
|
- `pvforecast<0..5>_surface_azimuth`: Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).
|
||||||
|
- `pvforecast<0..5>_userhorizon`: Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.
|
||||||
|
- `pvforecast<0..5>_peakpower`: Nominal power of PV system in kW.
|
||||||
|
- `pvforecast<0..5>_pvtechchoice`: PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.
|
||||||
|
- `pvforecast<0..5>_mountingplace`: Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.
|
||||||
|
- `pvforecast<0..5>_loss`: Sum of PV system losses in percent
|
||||||
|
- `pvforecast<0..5>_trackingtype`: 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.
|
||||||
|
- `pvforecast<0..5>_optimal_surface_tilt`: Calculate the optimum tilt angle. Ignored for two-axis tracking.
|
||||||
|
- `pvforecast<0..5>_optimalangles`: Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.
|
||||||
|
- `pvforecast<0..5>_albedo`: Proportion of the light hitting the ground that it reflects back.
|
||||||
|
- `pvforecast<0..5>_module_model`: Model of the PV modules of this plane.
|
||||||
|
- `pvforecast<0..5>_inverter_model`: Model of the inverter of this plane.
|
||||||
|
- `pvforecast<0..5>_inverter_paco`: AC power rating of the inverter. [W]
|
||||||
|
- `pvforecast<0..5>_modules_per_string`: Number of the PV modules of the strings of this plane.
|
||||||
|
- `pvforecast<0..5>_strings_per_inverter`: Number of the strings of the inverter of this plane.
|
||||||
|
- `pvforecastimport_file_path`: Path to the file to import PV forecast data from.
|
||||||
|
- `pvforecastimport_json`: JSON string, dictionary of PV forecast value lists.
|
||||||
|
|
||||||
|
### PVForecastAkkudoktor Provider
|
||||||
|
|
||||||
|
The `PVForecastAkkudoktor` provider retrieves the PV power forecast data directly from
|
||||||
|
**Akkudoktor.net**.
|
||||||
|
|
||||||
|
The following general configuration options of the PV system must be set:
|
||||||
|
|
||||||
|
- `latitude`: Latitude in decimal degrees, between -90 and 90, north is positive (ISO 19115) (°)"
|
||||||
|
- `longitude`: Longitude in decimal degrees, within -180 to 180 (°)
|
||||||
|
|
||||||
|
For each plane `<0..5>` of the PV system the following configuration options must be set:
|
||||||
|
|
||||||
|
- `pvforecast<0..5>_surface_tilt`: Tilt angle from horizontal plane. Ignored for two-axis tracking.
|
||||||
|
- `pvforecast<0..5>_surface_azimuth`: Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).
|
||||||
|
- `pvforecast<0..5>_userhorizon`: Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.
|
||||||
|
- `pvforecast<0..5>_inverter_paco`: AC power rating of the inverter. [W]
|
||||||
|
- `pvforecast<0..5>_peakpower`: Nominal power of PV system in kW.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```Python
|
||||||
|
{
|
||||||
|
"latitude": 50.1234,
|
||||||
|
"longitude": 9.7654,
|
||||||
|
"pvforecast_provider": "PVForecastAkkudoktor",
|
||||||
|
"pvforecast0_peakpower": 5.0,
|
||||||
|
"pvforecast0_surface_azimuth": -10,
|
||||||
|
"pvforecast0_surface_tilt": 7,
|
||||||
|
"pvforecast0_userhorizon": [20, 27, 22, 20],
|
||||||
|
"pvforecast0_inverter_paco": 10000,
|
||||||
|
"pvforecast1_peakpower": 4.8,
|
||||||
|
"pvforecast1_surface_azimuth": -90,
|
||||||
|
"pvforecast1_surface_tilt": 7,
|
||||||
|
"pvforecast1_userhorizon": [30, 30, 30, 50],
|
||||||
|
"pvforecast1_inverter_paco": 10000,
|
||||||
|
"pvforecast2_peakpower": 1.4,
|
||||||
|
"pvforecast2_surface_azimuth": -40,
|
||||||
|
"pvforecast2_surface_tilt": 60,
|
||||||
|
"pvforecast2_userhorizon": [60, 30, 0, 30],
|
||||||
|
"pvforecast2_inverter_paco": 2000,
|
||||||
|
"pvforecast3_peakpower": 1.6,
|
||||||
|
"pvforecast3_surface_azimuth": 5,
|
||||||
|
"pvforecast3_surface_tilt": 45,
|
||||||
|
"pvforecast3_userhorizon": [45, 25, 30, 60],
|
||||||
|
"pvforecast3_inverter_paco": 1400,
|
||||||
|
"pvforecast4_peakpower": None,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### PVForecastImport Provider
|
||||||
|
|
||||||
|
The `PVForecastImport` provider is designed to import PV forecast data from a file or a JSON
|
||||||
|
string. An external entity should update the file or JSON string whenever new prediction data
|
||||||
|
becomes available.
|
||||||
|
|
||||||
|
The prediction keys for the PV forecast data are:
|
||||||
|
|
||||||
|
- `pvforecast_ac_power`: Total DC power (W).
|
||||||
|
- `pvforecast_dc_power`: Total AC power (W).
|
||||||
|
|
||||||
|
The PV forecast data must be provided in one of the formats described in
|
||||||
|
<project:#prediction-import-providers>. The data source must be given in the
|
||||||
|
`pvforecastimport_file_path` or `pvforecastimport_json` configuration option.
|
||||||
|
|
||||||
|
## Weather Prediction
|
||||||
|
|
||||||
|
Prediction keys:
|
||||||
|
|
||||||
|
- `weather_dew_point`: Dew Point (°C)
|
||||||
|
- `weather_dhi`: Diffuse Horizontal Irradiance (W/m2)
|
||||||
|
- `weather_dni`: Direct Normal Irradiance (W/m2)
|
||||||
|
- `weather_feels_like`: Feels Like (°C)
|
||||||
|
- `weather_fog`: Fog (%)
|
||||||
|
- `weather_frost_chance`: Chance of Frost
|
||||||
|
- `weather_ghi`: Global Horizontal Irradiance (W/m2)
|
||||||
|
- `weather_high_clouds`: High Clouds (% Sky Obscured)
|
||||||
|
- `weather_low_clouds`: Low Clouds (% Sky Obscured)
|
||||||
|
- `weather_medium_clouds`: Medium Clouds (% Sky Obscured)
|
||||||
|
- `weather_ozone`: Ozone (du)
|
||||||
|
- `weather_precip_amt`: Precipitation Amount (mm)
|
||||||
|
- `weather_precip_prob`: Precipitation Probability (%)
|
||||||
|
- `weather_preciptable_water`: Precipitable Water (cm)
|
||||||
|
- `weather_precip_type`: Precipitation Type
|
||||||
|
- `weather_pressure`: Pressure (mb)
|
||||||
|
- `weather_relative_humidity`: Relative Humidity (%)
|
||||||
|
- `weather_temp_air`: Temperature (°C)
|
||||||
|
- `weather_total_clouds`: Total Clouds (% Sky Obscured)
|
||||||
|
- `weather_visibility`: Visibility (m)
|
||||||
|
- `weather_wind_direction`: "Wind Direction (°)
|
||||||
|
- `weather_wind_speed`: Wind Speed (kmph)
|
||||||
|
|
||||||
|
Configuration options:
|
||||||
|
|
||||||
|
- `weather_provider`: Load provider id of provider to be used.
|
||||||
|
|
||||||
|
- `BrightSky`: Retrieves from https://api.brightsky.dev.
|
||||||
|
- `ClearOutside`: Retrieves from https://clearoutside.com/forecast.
|
||||||
|
- `LoadImport`: Imports from a file or JSON string.
|
||||||
|
|
||||||
|
- `weatherimport_file_path`: Path to the file to import weatherforecast data from.
|
||||||
|
- `weatherimport_json`: JSON string, dictionary of weather forecast value lists.
|
||||||
|
|
||||||
|
### BrightSky Provider
|
||||||
|
|
||||||
|
The `BrightSky` provider retrieves the PV power forecast data directly from
|
||||||
|
[**BrightSky**](https://api.brightsky.dev).
|
||||||
|
|
||||||
|
The provider provides forecast data for the following prediction keys:
|
||||||
|
|
||||||
|
- `weather_dew_point`: Dew Point (°C)
|
||||||
|
- `weather_ghi`: Global Horizontal Irradiance (W/m2)
|
||||||
|
- `weather_precip_amt`: Precipitation Amount (mm)
|
||||||
|
- `weather_precip_prob`: Precipitation Probability (%)
|
||||||
|
- `weather_pressure`: Pressure (mb)
|
||||||
|
- `weather_relative_humidity`: Relative Humidity (%)
|
||||||
|
- `weather_temp_air`: Temperature (°C)
|
||||||
|
- `weather_total_clouds`: Total Clouds (% Sky Obscured)
|
||||||
|
- `weather_visibility`: Visibility (m)
|
||||||
|
- `weather_wind_direction`: "Wind Direction (°)
|
||||||
|
- `weather_wind_speed`: Wind Speed (kmph)
|
||||||
|
|
||||||
|
### ClearOutside Provider
|
||||||
|
|
||||||
|
The `ClearOutside` provider retrieves the PV power forecast data directly from
|
||||||
|
[**ClearOutside**](https://clearoutside.com/forecast).
|
||||||
|
|
||||||
|
The provider provides forecast data for the following prediction keys:
|
||||||
|
|
||||||
|
- `weather_dew_point`: Dew Point (°C)
|
||||||
|
- `weather_dhi`: Diffuse Horizontal Irradiance (W/m2)
|
||||||
|
- `weather_dni`: Direct Normal Irradiance (W/m2)
|
||||||
|
- `weather_feels_like`: Feels Like (°C)
|
||||||
|
- `weather_fog`: Fog (%)
|
||||||
|
- `weather_frost_chance`: Chance of Frost
|
||||||
|
- `weather_ghi`: Global Horizontal Irradiance (W/m2)
|
||||||
|
- `weather_high_clouds`: High Clouds (% Sky Obscured)
|
||||||
|
- `weather_low_clouds`: Low Clouds (% Sky Obscured)
|
||||||
|
- `weather_medium_clouds`: Medium Clouds (% Sky Obscured)
|
||||||
|
- `weather_ozone`: Ozone (du)
|
||||||
|
- `weather_precip_amt`: Precipitation Amount (mm)
|
||||||
|
- `weather_precip_prob`: Precipitation Probability (%)
|
||||||
|
- `weather_preciptable_water`: Precipitable Water (cm)
|
||||||
|
- `weather_precip_type`: Precipitation Type
|
||||||
|
- `weather_pressure`: Pressure (mb)
|
||||||
|
- `weather_relative_humidity`: Relative Humidity (%)
|
||||||
|
- `weather_temp_air`: Temperature (°C)
|
||||||
|
- `weather_total_clouds`: Total Clouds (% Sky Obscured)
|
||||||
|
- `weather_visibility`: Visibility (m)
|
||||||
|
- `weather_wind_direction`: "Wind Direction (°)
|
||||||
|
- `weather_wind_speed`: Wind Speed (kmph)
|
||||||
|
|
||||||
|
### WeatherImport Provider
|
||||||
|
|
||||||
|
The `WeatherImport` provider is designed to import weather forecast data from a file or a JSON
|
||||||
|
string. An external entity should update the file or JSON string whenever new prediction data
|
||||||
|
becomes available.
|
||||||
|
|
||||||
|
The prediction keys for the PV forecast data are:
|
||||||
|
|
||||||
|
- `weather_dew_point`: Dew Point (°C)
|
||||||
|
- `weather_dhi`: Diffuse Horizontal Irradiance (W/m2)
|
||||||
|
- `weather_dni`: Direct Normal Irradiance (W/m2)
|
||||||
|
- `weather_feels_like`: Feels Like (°C)
|
||||||
|
- `weather_fog`: Fog (%)
|
||||||
|
- `weather_frost_chance`: Chance of Frost
|
||||||
|
- `weather_ghi`: Global Horizontal Irradiance (W/m2)
|
||||||
|
- `weather_high_clouds`: High Clouds (% Sky Obscured)
|
||||||
|
- `weather_low_clouds`: Low Clouds (% Sky Obscured)
|
||||||
|
- `weather_medium_clouds`: Medium Clouds (% Sky Obscured)
|
||||||
|
- `weather_ozone`: Ozone (du)
|
||||||
|
- `weather_precip_amt`: Precipitation Amount (mm)
|
||||||
|
- `weather_precip_prob`: Precipitation Probability (%)
|
||||||
|
- `weather_preciptable_water`: Precipitable Water (cm)
|
||||||
|
- `weather_precip_type`: Precipitation Type
|
||||||
|
- `weather_pressure`: Pressure (mb)
|
||||||
|
- `weather_relative_humidity`: Relative Humidity (%)
|
||||||
|
- `weather_temp_air`: Temperature (°C)
|
||||||
|
- `weather_total_clouds`: Total Clouds (% Sky Obscured)
|
||||||
|
- `weather_visibility`: Visibility (m)
|
||||||
|
- `weather_wind_direction`: "Wind Direction (°)
|
||||||
|
- `weather_wind_speed`: Wind Speed (kmph)
|
||||||
|
|
||||||
|
The PV forecast data must be provided in one of the formats described in
|
||||||
|
<project:#prediction-import-providers>. The data source must be given in the
|
||||||
|
`weatherimport_file_path` or `pvforecastimport_json` configuration option.
|
7
docs/akkudoktoreos/serverapi.md
Normal file
7
docs/akkudoktoreos/serverapi.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
% SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# Server API
|
||||||
|
|
||||||
|
```{eval-sh}
|
||||||
|
./scripts/generate_openapi_md.py | ./scripts/extract_markdown.py --input-stdin --start-line "**Version**:"
|
||||||
|
```
|
@ -1,17 +0,0 @@
|
|||||||
..
|
|
||||||
SPDX-License-Identifier: Apache-2.0
|
|
||||||
File has to be of RST format to make openapi directive work correctly
|
|
||||||
|
|
||||||
.. _akkudoktoreos_server_api:
|
|
||||||
|
|
||||||
Server API
|
|
||||||
##########
|
|
||||||
|
|
||||||
For a more detailed documentation see the Swagger interface: `EOS OpenAPI Spec <https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/docs/akkudoktoreos/openapi.json>`_
|
|
||||||
|
|
||||||
.. openapi:: openapi.json
|
|
||||||
:examples:
|
|
||||||
|
|
||||||
..
|
|
||||||
Due to bugs in sphinxcontrib-openapi referenced request/response objects fail to render and anyOf is broken too.
|
|
||||||
:request:
|
|
@ -23,8 +23,8 @@ extensions = [
|
|||||||
"sphinx.ext.autosummary",
|
"sphinx.ext.autosummary",
|
||||||
"sphinx.ext.napoleon",
|
"sphinx.ext.napoleon",
|
||||||
"sphinx_rtd_theme",
|
"sphinx_rtd_theme",
|
||||||
# "sphinxcontrib.openapi", buggy
|
|
||||||
"myst_parser",
|
"myst_parser",
|
||||||
|
"sphinxcontrib.eval",
|
||||||
]
|
]
|
||||||
|
|
||||||
templates_path = ["_templates"]
|
templates_path = ["_templates"]
|
||||||
@ -80,7 +80,7 @@ myst_url_schemes = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
myst_number_code_blocks = ["typescript"]
|
myst_number_code_blocks = ["typescript"]
|
||||||
myst_heading_anchors = 2
|
myst_heading_anchors = 3
|
||||||
myst_footnote_transition = True
|
myst_footnote_transition = True
|
||||||
myst_dmath_double_inline = True
|
myst_dmath_double_inline = True
|
||||||
myst_enable_checkboxes = True
|
myst_enable_checkboxes = True
|
||||||
@ -117,9 +117,6 @@ autodoc_default_options = {
|
|||||||
# -- Options for autosummary -------------------------------------------------
|
# -- Options for autosummary -------------------------------------------------
|
||||||
autosummary_generate = True
|
autosummary_generate = True
|
||||||
|
|
||||||
# -- Options for openapi -----------------------------------------------------
|
|
||||||
# openapi_default_renderer = "httpdomain:old" buggy
|
|
||||||
|
|
||||||
# -- Options for napoleon -------------------------------------------------
|
# -- Options for napoleon -------------------------------------------------
|
||||||
napoleon_google_docstring = True
|
napoleon_google_docstring = True
|
||||||
napoleon_numpy_docstring = False
|
napoleon_numpy_docstring = False
|
||||||
|
3
docs/develop/CONTRIBUTING.md
Normal file
3
docs/develop/CONTRIBUTING.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
```{eval-sh}
|
||||||
|
./scripts/extract_markdown.py --input-file CONTRIBUTING.md
|
||||||
|
```
|
5
docs/develop/getting_started.md
Normal file
5
docs/develop/getting_started.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Getting Started
|
||||||
|
|
||||||
|
```{eval-sh}
|
||||||
|
./scripts/extract_markdown.py --input-file README.md --start-line "## Getting Involved"
|
||||||
|
```
|
@ -14,7 +14,9 @@ welcome.md
|
|||||||
akkudoktoreos/about.md
|
akkudoktoreos/about.md
|
||||||
develop/getting_started.md
|
develop/getting_started.md
|
||||||
develop/CONTRIBUTING.md
|
develop/CONTRIBUTING.md
|
||||||
akkudoktoreos/serverapi.rst
|
akkudoktoreos/prediction.md
|
||||||
|
akkudoktoreos/measurement.md
|
||||||
|
akkudoktoreos/serverapi.md
|
||||||
akkudoktoreos/api.rst
|
akkudoktoreos/api.rst
|
||||||
```
|
```
|
||||||
|
|
||||||
|
5887
openapi.json
Normal file
5887
openapi.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@ linkify-it-py==2.0.3
|
|||||||
myst-parser==4.0.0
|
myst-parser==4.0.0
|
||||||
sphinx==8.1.3
|
sphinx==8.1.3
|
||||||
sphinx_rtd_theme==3.0.2
|
sphinx_rtd_theme==3.0.2
|
||||||
sphinxcontrib-openapi==0.8.4
|
sphinxcontrib-eval==0.0.3
|
||||||
pytest==8.3.4
|
pytest==8.3.4
|
||||||
pytest-cov==6.0.0
|
pytest-cov==6.0.0
|
||||||
pytest-xprocess==1.0.2
|
pytest-xprocess==1.0.2
|
||||||
|
0
scripts/__init__.py
Normal file
0
scripts/__init__.py
Normal file
179
scripts/extract_markdown.py
Executable file
179
scripts/extract_markdown.py
Executable file
@ -0,0 +1,179 @@
|
|||||||
|
#!.venv/bin/python
|
||||||
|
r"""This module extracts a part of a markdown string from an input file or a given input string.
|
||||||
|
|
||||||
|
The extraction starts at a line that contains the content specified by the `--start-line` parameter
|
||||||
|
and ends at a line that contains the content specified by the `--end-line` parameter.
|
||||||
|
If `--start-line` is not specified, extraction starts from the beginning of the file or string.
|
||||||
|
If `--end-line` is not specified, extraction goes to the end of the file or string.
|
||||||
|
|
||||||
|
The extracted markdown string is written either to stdout or to the specified output file.
|
||||||
|
Additionally, the heading levels can be adjusted by specifying the `--heading-level` parameter.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
scripts/extract_markdown.py [--input-file INPUT_FILE | --input INPUT_STRING] [--start-line START_LINE] [--end-line END_LINE] [--output-file OUTPUT_FILE] [--heading-level HEADING_LEVEL]
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
--input-file : The file path to read the markdown content from.
|
||||||
|
--input : The markdown content as a string.
|
||||||
|
--start-line : Optional. The string content of the start line from where extraction begins.
|
||||||
|
--end-line : Optional. The string content of the end line where extraction ends.
|
||||||
|
--output-file : Optional. The file path to write the extracted markdown content to.
|
||||||
|
--heading-level: Optional. The number of additional `#` to add to markdown headings or to remove
|
||||||
|
from markdown headings if negative.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
scripts/extract_markdown.py --input-file input.md --start-line "# Start" --end-line "# End" --output-file output.md --heading-level 1
|
||||||
|
scripts/extract_markdown.py --input "# Start\n\nSome content here\n\n# End" --start-line "# Start" --end-line "# End" --output-file output.md --heading-level 1
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
This module extracts a part of a markdown string from an input file or a given input string.
|
||||||
|
|
||||||
|
The extraction starts at a line that contains the content specified by the `--start-line` parameter
|
||||||
|
and ends at a line that contains the content specified by the `--end-line` parameter.
|
||||||
|
If `--start-line` is not specified, extraction starts from the beginning of the file or string.
|
||||||
|
If `--end-line` is not specified, extraction goes to the end of the file or string.
|
||||||
|
|
||||||
|
The extracted markdown string is written either to stdout or to the specified output file.
|
||||||
|
Additionally, the heading levels can be adjusted by specifying the `--heading-level` parameter.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python extract_markdown.py [--input-file INPUT_FILE | --input INPUT_STRING | --input-stdin] [--start-line START_LINE] [--end-line END_LINE] [--output-file OUTPUT_FILE] [--heading-level HEADING_LEVEL]
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
--input-file : The file path to read the markdown content from.
|
||||||
|
--input : The markdown content as a string.
|
||||||
|
--input-stdin : Read markdown content from stdin.
|
||||||
|
--start-line : Optional. The string content of the start line from where extraction begins.
|
||||||
|
--end-line : Optional. The string content of the end line where extraction ends.
|
||||||
|
--output-file : Optional. The file path to write the extracted markdown content to.
|
||||||
|
--heading-level: Optional. The number of additional `#` to add to markdown headings or to remove from markdown headings if negative.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
python extract_markdown.py --input-file input.md --start-line "# Start" --end-line "# End" --output-file output.md --heading-level 1
|
||||||
|
python extract_markdown.py --input "# Start\n\nSome content here\n\n# End" --start-line "# Start" --end-line "# End" --output-file output.md --heading-level 1
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def adjust_heading_levels(line: str, heading_level: int) -> str:
|
||||||
|
"""Adjust the heading levels in a markdown line.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
line (str): The markdown line.
|
||||||
|
heading_level (int): The number of levels to adjust the headings by.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
adjusted_line (str): The line with adjusted heading levels.
|
||||||
|
"""
|
||||||
|
heading_pattern = re.compile(r"^(#+)\s")
|
||||||
|
match = heading_pattern.match(line)
|
||||||
|
if match:
|
||||||
|
current_level = len(match.group(1))
|
||||||
|
new_level = current_level + heading_level
|
||||||
|
if new_level > 0:
|
||||||
|
adjusted_line = "#" * new_level + line[current_level:]
|
||||||
|
else:
|
||||||
|
adjusted_line = line[current_level:]
|
||||||
|
else:
|
||||||
|
adjusted_line = line
|
||||||
|
return adjusted_line
|
||||||
|
|
||||||
|
|
||||||
|
def extract_markdown(content: str, start_line: str, end_line: str, heading_level: int) -> str:
|
||||||
|
"""Extract a part of a markdown string from given content.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
content (str): The markdown content.
|
||||||
|
start_line (str): The string content of the start line from where extraction begins.
|
||||||
|
end_line (str): The string content of the end line where extraction ends.
|
||||||
|
heading_level (int): The number of levels to adjust the headings by.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
extracted_content (str): Extracted markdown content as a string.
|
||||||
|
"""
|
||||||
|
extracted_content = []
|
||||||
|
lines = content.splitlines(True)
|
||||||
|
extracting = start_line is None
|
||||||
|
for line in lines:
|
||||||
|
if not extracting and start_line and start_line in line:
|
||||||
|
extracting = True
|
||||||
|
extracted_content.append(
|
||||||
|
adjust_heading_levels(line, heading_level)
|
||||||
|
) # Include start line in output
|
||||||
|
continue
|
||||||
|
if extracting and end_line and end_line in line:
|
||||||
|
extracting = False
|
||||||
|
break
|
||||||
|
if extracting:
|
||||||
|
extracted_content.append(adjust_heading_levels(line, heading_level))
|
||||||
|
return "".join(extracted_content)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main function to run the extraction of the markdown content."""
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Extract a part of a markdown string from an input file"
|
||||||
|
)
|
||||||
|
group = parser.add_mutually_exclusive_group(required=True)
|
||||||
|
group.add_argument("--input-file", type=str, help="File to read the markdown content from")
|
||||||
|
group.add_argument("--input", type=str, help="Markdown content as a string")
|
||||||
|
group.add_argument(
|
||||||
|
"--input-stdin", action="store_true", help="Read markdown content from stdin"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--start-line",
|
||||||
|
type=str,
|
||||||
|
default=None,
|
||||||
|
help="Optional. The string content of the start line",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--end-line", type=str, default=None, help="Optional. The string content of the end line"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--output-file",
|
||||||
|
type=str,
|
||||||
|
default=None,
|
||||||
|
help="File to write the extracted markdown content to",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--heading-level",
|
||||||
|
type=int,
|
||||||
|
default=0,
|
||||||
|
help="The number of additional `#` to add to markdown headings or to remove from markdown headings if negative",
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if args.input_file:
|
||||||
|
with open(args.input_file, "r") as f:
|
||||||
|
content = f.read()
|
||||||
|
elif args.input:
|
||||||
|
content = args.input
|
||||||
|
elif args.input_stdin:
|
||||||
|
content = sys.stdin.read()
|
||||||
|
else:
|
||||||
|
raise ValueError("No valid input source provided.")
|
||||||
|
|
||||||
|
extracted_content = extract_markdown(
|
||||||
|
content, args.start_line, args.end_line, args.heading_level
|
||||||
|
)
|
||||||
|
if args.output_file:
|
||||||
|
# Write to file
|
||||||
|
with open(args.output_file, "w") as f:
|
||||||
|
f.write(extracted_content)
|
||||||
|
else:
|
||||||
|
# Write to std output
|
||||||
|
print(extracted_content)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error during markdown extraction: {e}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
69
scripts/generate_openapi.py
Executable file
69
scripts/generate_openapi.py
Executable file
@ -0,0 +1,69 @@
|
|||||||
|
#!.venv/bin/python
|
||||||
|
"""This module generates the OpenAPI specification for the FastAPI application defined in `akkudoktoreos.server.fastapi_server`.
|
||||||
|
|
||||||
|
The script can be executed directly to generate the OpenAPI specification
|
||||||
|
either to the standard output or to a specified file.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
scripts/generate_openapi.py [--output-file OUTPUT_FILE]
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
--output-file : Optional. The file path to write the OpenAPI specification to.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
scripts/generate_openapi.py --output-file openapi.json
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from fastapi.openapi.utils import get_openapi
|
||||||
|
|
||||||
|
from akkudoktoreos.server.fastapi_server import app
|
||||||
|
|
||||||
|
|
||||||
|
def generate_openapi() -> dict:
|
||||||
|
"""Generate the OpenAPI specification.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
openapi_spec (dict): OpenAPI specification.
|
||||||
|
"""
|
||||||
|
openapi_spec = get_openapi(
|
||||||
|
title=app.title,
|
||||||
|
version=app.version,
|
||||||
|
openapi_version=app.openapi_version,
|
||||||
|
description=app.description,
|
||||||
|
routes=app.routes,
|
||||||
|
)
|
||||||
|
|
||||||
|
return openapi_spec
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main function to run the generation of the OpenAPI specification."""
|
||||||
|
parser = argparse.ArgumentParser(description="Generate OpenAPI Specification")
|
||||||
|
parser.add_argument(
|
||||||
|
"--output-file", type=str, default=None, help="File to write the OpenAPI Specification to"
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
openapi_spec = generate_openapi()
|
||||||
|
openapi_spec_str = json.dumps(openapi_spec, indent=2)
|
||||||
|
if args.output_file:
|
||||||
|
# Write to file
|
||||||
|
with open(args.output_file, "w") as f:
|
||||||
|
f.write(openapi_spec_str)
|
||||||
|
else:
|
||||||
|
# Write to std output
|
||||||
|
print(openapi_spec_str)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error during OpenAPI specification generation: {e}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
239
scripts/generate_openapi_md.py
Executable file
239
scripts/generate_openapi_md.py
Executable file
@ -0,0 +1,239 @@
|
|||||||
|
#!.venv/bin/python
|
||||||
|
"""Utility functions for OpenAPI specification conversion tasks."""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if __package__ is None or __package__ == "":
|
||||||
|
# uses current directory visibility
|
||||||
|
import generate_openapi
|
||||||
|
else:
|
||||||
|
# uses current package visibility
|
||||||
|
from . import generate_openapi
|
||||||
|
|
||||||
|
|
||||||
|
def extract_info(openapi_json: dict) -> dict:
|
||||||
|
"""Extract basic information from OpenAPI JSON.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
openapi_json (dict): The OpenAPI specification as a Python dictionary.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: A dictionary containing the title, version, description, and base_url.
|
||||||
|
"""
|
||||||
|
info = openapi_json.get("info", {})
|
||||||
|
servers = openapi_json.get("servers", [{}])
|
||||||
|
|
||||||
|
return {
|
||||||
|
"title": info.get("title", "API Documentation"),
|
||||||
|
"version": info.get("version", "1.0.0"),
|
||||||
|
"description": info.get("description", "No description provided."),
|
||||||
|
"base_url": servers[0].get("url", "No base URL provided."),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def format_authentication(security_schemes: dict) -> str:
|
||||||
|
"""Format the authentication section for the Markdown.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
security_schemes (dict): The security schemes from the OpenAPI spec.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The formatted authentication section in Markdown.
|
||||||
|
"""
|
||||||
|
if not security_schemes:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
markdown = "## Authentication\n\n"
|
||||||
|
for scheme, details in security_schemes.items():
|
||||||
|
auth_type = details.get("type", "unknown")
|
||||||
|
markdown += f"- **{scheme}**: {auth_type}\n\n"
|
||||||
|
return markdown
|
||||||
|
|
||||||
|
|
||||||
|
def format_parameters(parameters: list) -> str:
|
||||||
|
"""Format the parameters section for the Markdown.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
parameters (list): The list of parameters from an endpoint.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The formatted parameters section in Markdown.
|
||||||
|
"""
|
||||||
|
if not parameters:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
markdown = "**Parameters**:\n\n"
|
||||||
|
for param in parameters:
|
||||||
|
name = param.get("name", "unknown")
|
||||||
|
location = param.get("in", "unknown")
|
||||||
|
required = param.get("required", False)
|
||||||
|
description = param.get("description", "No description provided.")
|
||||||
|
markdown += (
|
||||||
|
f"- `{name}` ({location}, {'required' if required else 'optional'}): {description}\n\n"
|
||||||
|
)
|
||||||
|
return markdown
|
||||||
|
|
||||||
|
|
||||||
|
def format_request_body(request_body: dict) -> str:
|
||||||
|
"""Format the request body section for the Markdown.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request_body (dict): The request body content from an endpoint.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The formatted request body section in Markdown.
|
||||||
|
"""
|
||||||
|
if not request_body:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
markdown = "**Request Body**:\n\n"
|
||||||
|
for content_type, schema in request_body.items():
|
||||||
|
markdown += f"- `{content_type}`: {json.dumps(schema.get('schema', {}), indent=2)}\n\n"
|
||||||
|
return markdown
|
||||||
|
|
||||||
|
|
||||||
|
def format_responses(responses: dict) -> str:
|
||||||
|
"""Format the responses section for the Markdown.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
responses (dict): The responses from an endpoint.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The formatted responses section in Markdown.
|
||||||
|
"""
|
||||||
|
if not responses:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
markdown = "**Responses**:\n\n"
|
||||||
|
for status, response in responses.items():
|
||||||
|
desc = response.get("description", "No description provided.")
|
||||||
|
markdown += f"- **{status}**: {desc}\n\n"
|
||||||
|
return markdown
|
||||||
|
|
||||||
|
|
||||||
|
def format_endpoint(path: str, method: str, details: dict) -> str:
|
||||||
|
"""Format a single endpoint's details for the Markdown.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path (str): The endpoint path.
|
||||||
|
method (str): The HTTP method.
|
||||||
|
details (dict): The details of the endpoint.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The formatted endpoint section in Markdown.
|
||||||
|
"""
|
||||||
|
link_summary = (
|
||||||
|
details.get("summary", "<summary missing>")
|
||||||
|
.lower()
|
||||||
|
.strip()
|
||||||
|
.replace(" ", "_")
|
||||||
|
.replace("-", "_")
|
||||||
|
)
|
||||||
|
link_path = (
|
||||||
|
path.lower().strip().replace("/", "_").replace(".", "_").replace("{", "_").replace("}", "_")
|
||||||
|
)
|
||||||
|
link_method = f"_{method.lower()})"
|
||||||
|
# [local](http://localhost:8503/docs#/default/fastapi_config_get_v1_config_get)
|
||||||
|
local_path = (
|
||||||
|
"[local](http://localhost:8503/docs#/default/" + link_summary + link_path + link_method
|
||||||
|
)
|
||||||
|
# [swagger](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_strompreis_strompreis_get)
|
||||||
|
swagger_path = (
|
||||||
|
"[swagger](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/"
|
||||||
|
+ link_summary
|
||||||
|
+ link_path
|
||||||
|
+ link_method
|
||||||
|
)
|
||||||
|
|
||||||
|
markdown = f"## {method.upper()} {path}\n\n"
|
||||||
|
|
||||||
|
markdown += f"**Links**: {local_path}, {swagger_path}\n\n"
|
||||||
|
|
||||||
|
summary = details.get("summary", None)
|
||||||
|
if summary:
|
||||||
|
markdown += f"{summary}\n\n"
|
||||||
|
|
||||||
|
description = details.get("description", None)
|
||||||
|
if description:
|
||||||
|
markdown += "```\n"
|
||||||
|
markdown += f"{description}"
|
||||||
|
markdown += "\n```\n\n"
|
||||||
|
|
||||||
|
markdown += format_parameters(details.get("parameters", []))
|
||||||
|
markdown += format_request_body(details.get("requestBody", {}).get("content", {}))
|
||||||
|
markdown += format_responses(details.get("responses", {}))
|
||||||
|
markdown += "---\n\n"
|
||||||
|
|
||||||
|
return markdown
|
||||||
|
|
||||||
|
|
||||||
|
def openapi_to_markdown(openapi_json: dict) -> str:
|
||||||
|
"""Convert OpenAPI JSON specification to a Markdown representation.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
openapi_json (dict): The OpenAPI specification as a Python dictionary.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The Markdown representation of the OpenAPI spec.
|
||||||
|
"""
|
||||||
|
info = extract_info(openapi_json)
|
||||||
|
markdown = f"# {info['title']}\n\n"
|
||||||
|
markdown += f"**Version**: `{info['version']}`\n\n"
|
||||||
|
markdown += f"**Description**: {info['description']}\n\n"
|
||||||
|
markdown += f"**Base URL**: `{info['base_url']}`\n\n"
|
||||||
|
|
||||||
|
security_schemes = openapi_json.get("components", {}).get("securitySchemes", {})
|
||||||
|
markdown += format_authentication(security_schemes)
|
||||||
|
|
||||||
|
markdown += "**Endpoints**:\n\n"
|
||||||
|
paths = openapi_json.get("paths", {})
|
||||||
|
for path, methods in paths.items():
|
||||||
|
for method, details in methods.items():
|
||||||
|
markdown += format_endpoint(path, method, details)
|
||||||
|
|
||||||
|
# Assure the is no double \n at end of file
|
||||||
|
markdown = markdown.rstrip("\n")
|
||||||
|
markdown += "\n"
|
||||||
|
|
||||||
|
return markdown
|
||||||
|
|
||||||
|
|
||||||
|
def generate_openapi_md() -> str:
|
||||||
|
"""Generate OpenAPI specification in Markdown.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The Markdown representation of the OpenAPI spec.
|
||||||
|
"""
|
||||||
|
openapi_spec = generate_openapi.generate_openapi()
|
||||||
|
openapi_md = openapi_to_markdown(openapi_spec)
|
||||||
|
return openapi_md
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main function to run the generation of the OpenAPI specification as Markdown."""
|
||||||
|
parser = argparse.ArgumentParser(description="Generate OpenAPI Specification as Markdown")
|
||||||
|
parser.add_argument(
|
||||||
|
"--output-file", type=str, default=None, help="File to write the OpenAPI Specification to"
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
openapi_md = generate_openapi_md()
|
||||||
|
if args.output_file:
|
||||||
|
# Write to file
|
||||||
|
with open(args.output_file, "w") as f:
|
||||||
|
f.write(openapi_md)
|
||||||
|
else:
|
||||||
|
# Write to std output
|
||||||
|
print(openapi_md)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error during OpenAPI specification generation: {e}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
@ -11,8 +11,6 @@ logger = get_logger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class LoadCommonSettings(SettingsBaseModel):
|
class LoadCommonSettings(SettingsBaseModel):
|
||||||
# Load 0
|
|
||||||
load_provider: Optional[str] = Field(
|
load_provider: Optional[str] = Field(
|
||||||
default=None, description="Load provider id of provider to be used."
|
default=None, description="Load provider id of provider to be used."
|
||||||
)
|
)
|
||||||
load_name: Optional[str] = Field(default=None, description="Name of the load source.")
|
|
||||||
|
@ -18,13 +18,12 @@ logger = get_logger(__name__)
|
|||||||
class LoadDataRecord(PredictionRecord):
|
class LoadDataRecord(PredictionRecord):
|
||||||
"""Represents a load data record containing various load attributes at a specific datetime."""
|
"""Represents a load data record containing various load attributes at a specific datetime."""
|
||||||
|
|
||||||
load_mean: Optional[float] = Field(default=None, description="Predicted load mean value (W)")
|
load_mean: Optional[float] = Field(default=None, description="Predicted load mean value (W).")
|
||||||
load_std: Optional[float] = Field(
|
load_std: Optional[float] = Field(
|
||||||
default=None, description="Predicted load standard deviation (W)"
|
default=None, description="Predicted load standard deviation (W)."
|
||||||
)
|
)
|
||||||
|
|
||||||
load_mean_adjusted: Optional[float] = Field(
|
load_mean_adjusted: Optional[float] = Field(
|
||||||
default=None, description="Predicted load mean value adjusted by load measurement (W)"
|
default=None, description="Predicted load mean value adjusted by load measurement (W)."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,8 +18,8 @@ logger = get_logger(__name__)
|
|||||||
class PVForecastDataRecord(PredictionRecord):
|
class PVForecastDataRecord(PredictionRecord):
|
||||||
"""Represents a pvforecast data record containing various pvforecast attributes at a specific datetime."""
|
"""Represents a pvforecast data record containing various pvforecast attributes at a specific datetime."""
|
||||||
|
|
||||||
pvforecast_dc_power: Optional[float] = Field(default=None, description="Total DC power (W)")
|
pvforecast_dc_power: Optional[float] = Field(default=None, description="Total DC power (W).")
|
||||||
pvforecast_ac_power: Optional[float] = Field(default=None, description="Total AC power (W)")
|
pvforecast_ac_power: Optional[float] = Field(default=None, description="Total AC power (W).")
|
||||||
|
|
||||||
|
|
||||||
class PVForecastProvider(PredictionProvider):
|
class PVForecastProvider(PredictionProvider):
|
||||||
|
@ -23,13 +23,12 @@ class PVForecastImportCommonSettings(SettingsBaseModel):
|
|||||||
"""Common settings for pvforecast data import from file or JSON string."""
|
"""Common settings for pvforecast data import from file or JSON string."""
|
||||||
|
|
||||||
pvforecastimport_file_path: Optional[Union[str, Path]] = Field(
|
pvforecastimport_file_path: Optional[Union[str, Path]] = Field(
|
||||||
default=None, description="Path to the file to import pvforecast data from."
|
default=None, description="Path to the file to import PV forecast data from."
|
||||||
)
|
)
|
||||||
|
|
||||||
pvforecastimport_json: Optional[str] = Field(
|
pvforecastimport_json: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="JSON string, dictionary of PV forecast float value lists."
|
description="JSON string, dictionary of PV forecast value lists.",
|
||||||
"Keys are 'pvforecast_dc_power', 'pvforecast_ac_power'.",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validators
|
# Validators
|
||||||
|
@ -56,7 +56,7 @@ class WeatherDataRecord(PredictionRecord):
|
|||||||
default=None, description="Low Clouds (% Sky Obscured)"
|
default=None, description="Low Clouds (% Sky Obscured)"
|
||||||
)
|
)
|
||||||
weather_medium_clouds: Optional[float] = Field(
|
weather_medium_clouds: Optional[float] = Field(
|
||||||
None, description="Medium Clouds (% Sky Obscured)"
|
default=None, description="Medium Clouds (% Sky Obscured)"
|
||||||
)
|
)
|
||||||
weather_high_clouds: Optional[float] = Field(
|
weather_high_clouds: Optional[float] = Field(
|
||||||
default=None, description="High Clouds (% Sky Obscured)"
|
default=None, description="High Clouds (% Sky Obscured)"
|
||||||
|
@ -219,7 +219,9 @@ def fastapi_measurement_keys_get() -> list[str]:
|
|||||||
|
|
||||||
|
|
||||||
@app.get("/v1/measurement/load-mr/series/by-name")
|
@app.get("/v1/measurement/load-mr/series/by-name")
|
||||||
def fastapi_measurement_load_mr_series_by_name_get(name: str) -> PydanticDateTimeSeries:
|
def fastapi_measurement_load_mr_series_by_name_get(
|
||||||
|
name: Annotated[str, Query(description="Load name.")],
|
||||||
|
) -> PydanticDateTimeSeries:
|
||||||
"""Get the meter reading of given load name as series."""
|
"""Get the meter reading of given load name as series."""
|
||||||
key = measurement_eos.name_to_key(name=name, topic="measurement_load")
|
key = measurement_eos.name_to_key(name=name, topic="measurement_load")
|
||||||
if key is None:
|
if key is None:
|
||||||
@ -234,7 +236,9 @@ def fastapi_measurement_load_mr_series_by_name_get(name: str) -> PydanticDateTim
|
|||||||
|
|
||||||
@app.put("/v1/measurement/load-mr/value/by-name")
|
@app.put("/v1/measurement/load-mr/value/by-name")
|
||||||
def fastapi_measurement_load_mr_value_by_name_put(
|
def fastapi_measurement_load_mr_value_by_name_put(
|
||||||
datetime: Any, name: str, value: Union[float | str]
|
datetime: Annotated[str, Query(description="Datetime.")],
|
||||||
|
name: Annotated[str, Query(description="Load name.")],
|
||||||
|
value: Union[float | str],
|
||||||
) -> PydanticDateTimeSeries:
|
) -> PydanticDateTimeSeries:
|
||||||
"""Merge the meter reading of given load name and value into EOS measurements at given datetime."""
|
"""Merge the meter reading of given load name and value into EOS measurements at given datetime."""
|
||||||
key = measurement_eos.name_to_key(name=name, topic="measurement_load")
|
key = measurement_eos.name_to_key(name=name, topic="measurement_load")
|
||||||
@ -251,7 +255,7 @@ def fastapi_measurement_load_mr_value_by_name_put(
|
|||||||
|
|
||||||
@app.put("/v1/measurement/load-mr/series/by-name")
|
@app.put("/v1/measurement/load-mr/series/by-name")
|
||||||
def fastapi_measurement_load_mr_series_by_name_put(
|
def fastapi_measurement_load_mr_series_by_name_put(
|
||||||
name: str, series: PydanticDateTimeSeries
|
name: Annotated[str, Query(description="Load name.")], series: PydanticDateTimeSeries
|
||||||
) -> PydanticDateTimeSeries:
|
) -> PydanticDateTimeSeries:
|
||||||
"""Merge the meter readings series of given load name into EOS measurements at given datetime."""
|
"""Merge the meter readings series of given load name into EOS measurements at given datetime."""
|
||||||
key = measurement_eos.name_to_key(name=name, topic="measurement_load")
|
key = measurement_eos.name_to_key(name=name, topic="measurement_load")
|
||||||
@ -268,7 +272,9 @@ def fastapi_measurement_load_mr_series_by_name_put(
|
|||||||
|
|
||||||
|
|
||||||
@app.get("/v1/measurement/series")
|
@app.get("/v1/measurement/series")
|
||||||
def fastapi_measurement_series_get(key: str) -> PydanticDateTimeSeries:
|
def fastapi_measurement_series_get(
|
||||||
|
key: Annotated[str, Query(description="Prediction key.")],
|
||||||
|
) -> PydanticDateTimeSeries:
|
||||||
"""Get the measurements of given key as series."""
|
"""Get the measurements of given key as series."""
|
||||||
if key not in measurement_eos.record_keys:
|
if key not in measurement_eos.record_keys:
|
||||||
raise HTTPException(status_code=404, detail=f"Key '{key}' not available.")
|
raise HTTPException(status_code=404, detail=f"Key '{key}' not available.")
|
||||||
@ -278,7 +284,9 @@ def fastapi_measurement_series_get(key: str) -> PydanticDateTimeSeries:
|
|||||||
|
|
||||||
@app.put("/v1/measurement/value")
|
@app.put("/v1/measurement/value")
|
||||||
def fastapi_measurement_value_put(
|
def fastapi_measurement_value_put(
|
||||||
datetime: Any, key: str, value: Union[float | str]
|
datetime: Annotated[str, Query(description="Datetime.")],
|
||||||
|
key: Annotated[str, Query(description="Prediction key.")],
|
||||||
|
value: Union[float | str],
|
||||||
) -> PydanticDateTimeSeries:
|
) -> PydanticDateTimeSeries:
|
||||||
"""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."""
|
||||||
if key not in measurement_eos.record_keys:
|
if key not in measurement_eos.record_keys:
|
||||||
@ -290,7 +298,7 @@ def fastapi_measurement_value_put(
|
|||||||
|
|
||||||
@app.put("/v1/measurement/series")
|
@app.put("/v1/measurement/series")
|
||||||
def fastapi_measurement_series_put(
|
def fastapi_measurement_series_put(
|
||||||
key: str, series: PydanticDateTimeSeries
|
key: Annotated[str, Query(description="Prediction key.")], series: PydanticDateTimeSeries
|
||||||
) -> PydanticDateTimeSeries:
|
) -> PydanticDateTimeSeries:
|
||||||
"""Merge measurement given as series into given key."""
|
"""Merge measurement given as series into given key."""
|
||||||
if key not in measurement_eos.record_keys:
|
if key not in measurement_eos.record_keys:
|
||||||
@ -323,16 +331,23 @@ def fastapi_prediction_keys_get() -> list[str]:
|
|||||||
|
|
||||||
@app.get("/v1/prediction/series")
|
@app.get("/v1/prediction/series")
|
||||||
def fastapi_prediction_series_get(
|
def fastapi_prediction_series_get(
|
||||||
key: str,
|
key: Annotated[str, Query(description="Prediction key.")],
|
||||||
start_datetime: Optional[str] = None,
|
start_datetime: Annotated[
|
||||||
end_datetime: Optional[str] = None,
|
Optional[str],
|
||||||
|
Query(description="Starting datetime (inclusive)."),
|
||||||
|
] = None,
|
||||||
|
end_datetime: Annotated[
|
||||||
|
Optional[str],
|
||||||
|
Query(description="Ending datetime (exclusive)."),
|
||||||
|
] = None,
|
||||||
) -> PydanticDateTimeSeries:
|
) -> PydanticDateTimeSeries:
|
||||||
"""Get prediction for given key within given date range as series.
|
"""Get prediction for given key within given date range as series.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
start_datetime: Starting datetime (inclusive).
|
key (str): Prediction key
|
||||||
|
start_datetime (Optional[str]): Starting datetime (inclusive).
|
||||||
Defaults to start datetime of latest prediction.
|
Defaults to start datetime of latest prediction.
|
||||||
end_datetime: Ending datetime (exclusive).
|
end_datetime (Optional[str]: Ending datetime (exclusive).
|
||||||
Defaults to end datetime of latest prediction.
|
Defaults to end datetime of latest prediction.
|
||||||
"""
|
"""
|
||||||
if key not in prediction_eos.record_keys:
|
if key not in prediction_eos.record_keys:
|
||||||
@ -353,19 +368,29 @@ def fastapi_prediction_series_get(
|
|||||||
|
|
||||||
@app.get("/v1/prediction/list")
|
@app.get("/v1/prediction/list")
|
||||||
def fastapi_prediction_list_get(
|
def fastapi_prediction_list_get(
|
||||||
key: str,
|
key: Annotated[str, Query(description="Prediction key.")],
|
||||||
start_datetime: Optional[str] = None,
|
start_datetime: Annotated[
|
||||||
end_datetime: Optional[str] = None,
|
Optional[str],
|
||||||
interval: Optional[str] = None,
|
Query(description="Starting datetime (inclusive)."),
|
||||||
|
] = None,
|
||||||
|
end_datetime: Annotated[
|
||||||
|
Optional[str],
|
||||||
|
Query(description="Ending datetime (exclusive)."),
|
||||||
|
] = None,
|
||||||
|
interval: Annotated[
|
||||||
|
Optional[str],
|
||||||
|
Query(description="Time duration for each interval."),
|
||||||
|
] = None,
|
||||||
) -> List[Any]:
|
) -> List[Any]:
|
||||||
"""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:
|
||||||
start_datetime: Starting datetime (inclusive).
|
key (str): Prediction key
|
||||||
|
start_datetime (Optional[str]): Starting datetime (inclusive).
|
||||||
Defaults to start datetime of latest prediction.
|
Defaults to start datetime of latest prediction.
|
||||||
end_datetime: Ending datetime (exclusive).
|
end_datetime (Optional[str]: Ending datetime (exclusive).
|
||||||
Defaults to end datetime of latest prediction.
|
Defaults to end datetime of latest prediction.
|
||||||
interval: Time duration for each interval
|
interval (Optional[str]): Time duration for each interval.
|
||||||
Defaults to 1 hour.
|
Defaults to 1 hour.
|
||||||
"""
|
"""
|
||||||
if key not in prediction_eos.record_keys:
|
if key not in prediction_eos.record_keys:
|
||||||
@ -640,26 +665,24 @@ def site_map() -> RedirectResponse:
|
|||||||
|
|
||||||
|
|
||||||
# Keep the proxy last to handle all requests that are not taken by the Rest API.
|
# Keep the proxy last to handle all requests that are not taken by the Rest API.
|
||||||
# Also keep the single endpoints for delete, get, post, put to assure openapi.json is always build
|
|
||||||
# the same way for testing.
|
|
||||||
|
|
||||||
|
|
||||||
@app.delete("/{path:path}")
|
@app.delete("/{path:path}", include_in_schema=False)
|
||||||
async def proxy_delete(request: Request, path: str) -> Response:
|
async def proxy_delete(request: Request, path: str) -> Response:
|
||||||
return await proxy(request, path)
|
return await proxy(request, path)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/{path:path}")
|
@app.get("/{path:path}", include_in_schema=False)
|
||||||
async def proxy_get(request: Request, path: str) -> Response:
|
async def proxy_get(request: Request, path: str) -> Response:
|
||||||
return await proxy(request, path)
|
return await proxy(request, path)
|
||||||
|
|
||||||
|
|
||||||
@app.post("/{path:path}")
|
@app.post("/{path:path}", include_in_schema=False)
|
||||||
async def proxy_post(request: Request, path: str) -> Response:
|
async def proxy_post(request: Request, path: str) -> Response:
|
||||||
return await proxy(request, path)
|
return await proxy(request, path)
|
||||||
|
|
||||||
|
|
||||||
@app.put("/{path:path}")
|
@app.put("/{path:path}", include_in_schema=False)
|
||||||
async def proxy_put(request: Request, path: str) -> Response:
|
async def proxy_put(request: Request, path: str) -> Response:
|
||||||
return await proxy(request, path)
|
return await proxy(request, path)
|
||||||
|
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
import json
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from fastapi.openapi.utils import get_openapi
|
|
||||||
|
|
||||||
from akkudoktoreos.server.fastapi_server import app
|
|
||||||
|
|
||||||
|
|
||||||
def generate_openapi(filename: str | Path = "openapi.json"):
|
|
||||||
with open(filename, "w") as f:
|
|
||||||
json.dump(
|
|
||||||
get_openapi(
|
|
||||||
title=app.title,
|
|
||||||
version=app.version,
|
|
||||||
openapi_version=app.openapi_version,
|
|
||||||
description=app.description,
|
|
||||||
routes=app.routes,
|
|
||||||
),
|
|
||||||
f,
|
|
||||||
indent=2,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
generate_openapi()
|
|
@ -1,27 +1,56 @@
|
|||||||
import json
|
import json
|
||||||
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
|
||||||
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."""
|
||||||
old_spec_path = DIR_PROJECT_ROOT / "docs" / "akkudoktoreos" / "openapi.json"
|
expected_spec_path = DIR_PROJECT_ROOT / "openapi.json"
|
||||||
new_spec_path = DIR_TESTDATA / "openapi-new.json"
|
new_spec_path = DIR_TESTDATA / "openapi-new.json"
|
||||||
|
expected_spec_md_path = DIR_TESTDATA / "openapi.md"
|
||||||
|
new_spec_md_path = DIR_TESTDATA / "openapi-new.md"
|
||||||
|
|
||||||
|
with open(expected_spec_path) as f_expected:
|
||||||
|
expected_spec = json.load(f_expected)
|
||||||
|
with open(expected_spec_md_path) as f_expected:
|
||||||
|
expected_spec_md = f_expected.read()
|
||||||
|
|
||||||
# Patch get_config and import within guard to patch global variables within the fastapi_server module.
|
# Patch get_config and import within guard to patch global variables within the fastapi_server module.
|
||||||
with patch("akkudoktoreos.config.config.get_config", return_value=config_eos):
|
with patch("akkudoktoreos.config.config.get_config", return_value=config_eos):
|
||||||
from generate_openapi import generate_openapi
|
# Ensure the script works correctly as part of a package
|
||||||
|
root_dir = Path(__file__).resolve().parent.parent
|
||||||
|
sys.path.insert(0, str(root_dir))
|
||||||
|
from scripts import generate_openapi, generate_openapi_md
|
||||||
|
|
||||||
generate_openapi(new_spec_path)
|
spec = generate_openapi.generate_openapi()
|
||||||
with open(new_spec_path) as f_new:
|
spec_md = generate_openapi_md.generate_openapi_md()
|
||||||
new_spec = json.load(f_new)
|
|
||||||
with open(old_spec_path) as f_old:
|
with open(new_spec_path, "w") as f_new:
|
||||||
old_spec = json.load(f_old)
|
json.dump(spec, f_new, indent=4, sort_keys=True)
|
||||||
|
with open(new_spec_md_path, "w") as f_new:
|
||||||
|
f_new.write(spec_md)
|
||||||
|
|
||||||
# Serialize to ensure comparison is consistent
|
# Serialize to ensure comparison is consistent
|
||||||
new_spec = json.dumps(new_spec, indent=4, sort_keys=True)
|
spec_str = json.dumps(spec, indent=4, sort_keys=True)
|
||||||
old_spec = json.dumps(old_spec, indent=4, sort_keys=True)
|
expected_spec_str = json.dumps(expected_spec, indent=4, sort_keys=True)
|
||||||
|
|
||||||
assert new_spec == old_spec
|
try:
|
||||||
|
assert spec_str == expected_spec_str
|
||||||
|
except AssertionError as e:
|
||||||
|
pytest.fail(
|
||||||
|
f"Expected {new_spec_path} to equal {expected_spec_path}.\n"
|
||||||
|
+ f"If ok: cp {new_spec_path} {expected_spec_path}\n"
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
assert spec_md == expected_spec_md
|
||||||
|
except AssertionError as e:
|
||||||
|
pytest.fail(
|
||||||
|
f"Expected {new_spec_md_path} to equal {expected_spec_md_path}.\n"
|
||||||
|
+ f"If ok: cp {new_spec_md_path} {expected_spec_md_path}\n"
|
||||||
|
)
|
||||||
|
569
tests/testdata/openapi.md
vendored
Normal file
569
tests/testdata/openapi.md
vendored
Normal file
@ -0,0 +1,569 @@
|
|||||||
|
# Akkudoktor-EOS
|
||||||
|
|
||||||
|
**Version**: `0.0.1`
|
||||||
|
|
||||||
|
**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.
|
||||||
|
|
||||||
|
**Base URL**: `No base URL provided.`
|
||||||
|
|
||||||
|
**Endpoints**:
|
||||||
|
|
||||||
|
## GET /v1/config
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_get_v1_config_get), [swagger](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_get_v1_config_get)
|
||||||
|
|
||||||
|
Fastapi Config Get
|
||||||
|
|
||||||
|
```
|
||||||
|
Get the current configuration.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PUT /v1/config
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_config_put_v1_config_put), [swagger](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_config_put_v1_config_put)
|
||||||
|
|
||||||
|
Fastapi Config Put
|
||||||
|
|
||||||
|
```
|
||||||
|
Merge settings into current configuration.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
settings (SettingsEOS): The settings to merge into the current configuration.
|
||||||
|
save (Optional[bool]): Save the resulting configuration to the configuration file.
|
||||||
|
Defaults to False.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
|
||||||
|
- `save` (query, optional): No description provided.
|
||||||
|
|
||||||
|
**Request Body**:
|
||||||
|
|
||||||
|
- `application/json`: {
|
||||||
|
"$ref": "#/components/schemas/SettingsEOS"
|
||||||
|
}
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
- **422**: Validation Error
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## GET /v1/measurement/keys
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_keys_get_v1_measurement_keys_get), [swagger](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)
|
||||||
|
|
||||||
|
Fastapi Measurement Keys Get
|
||||||
|
|
||||||
|
```
|
||||||
|
Get a list of available measurement keys.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## GET /v1/measurement/load-mr/series/by-name
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_load_mr_series_by_name_get_v1_measurement_load-mr_series_by-name_get), [swagger](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_measurement_load_mr_series_by_name_get_v1_measurement_load-mr_series_by-name_get)
|
||||||
|
|
||||||
|
Fastapi Measurement Load Mr Series By Name Get
|
||||||
|
|
||||||
|
```
|
||||||
|
Get the meter reading of given load name as series.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
|
||||||
|
- `name` (query, required): Load name.
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
- **422**: Validation Error
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PUT /v1/measurement/load-mr/series/by-name
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_load_mr_series_by_name_put_v1_measurement_load-mr_series_by-name_put), [swagger](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_measurement_load_mr_series_by_name_put_v1_measurement_load-mr_series_by-name_put)
|
||||||
|
|
||||||
|
Fastapi Measurement Load Mr Series By Name Put
|
||||||
|
|
||||||
|
```
|
||||||
|
Merge the meter readings series of given load name into EOS measurements at given datetime.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
|
||||||
|
- `name` (query, required): Load name.
|
||||||
|
|
||||||
|
**Request Body**:
|
||||||
|
|
||||||
|
- `application/json`: {
|
||||||
|
"$ref": "#/components/schemas/PydanticDateTimeSeries"
|
||||||
|
}
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
- **422**: Validation Error
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PUT /v1/measurement/load-mr/value/by-name
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_load_mr_value_by_name_put_v1_measurement_load-mr_value_by-name_put), [swagger](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_measurement_load_mr_value_by_name_put_v1_measurement_load-mr_value_by-name_put)
|
||||||
|
|
||||||
|
Fastapi Measurement Load Mr Value By Name Put
|
||||||
|
|
||||||
|
```
|
||||||
|
Merge the meter reading of given load name and value into EOS measurements at given datetime.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
|
||||||
|
- `datetime` (query, required): Datetime.
|
||||||
|
|
||||||
|
- `name` (query, required): Load name.
|
||||||
|
|
||||||
|
- `value` (query, required): No description provided.
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
- **422**: Validation Error
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## GET /v1/measurement/series
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_series_get_v1_measurement_series_get), [swagger](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)
|
||||||
|
|
||||||
|
Fastapi Measurement Series Get
|
||||||
|
|
||||||
|
```
|
||||||
|
Get the measurements of given key as series.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
|
||||||
|
- `key` (query, required): Prediction key.
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
- **422**: Validation Error
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PUT /v1/measurement/series
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_series_put_v1_measurement_series_put), [swagger](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)
|
||||||
|
|
||||||
|
Fastapi Measurement Series Put
|
||||||
|
|
||||||
|
```
|
||||||
|
Merge measurement given as series into given key.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
|
||||||
|
- `key` (query, required): Prediction key.
|
||||||
|
|
||||||
|
**Request Body**:
|
||||||
|
|
||||||
|
- `application/json`: {
|
||||||
|
"$ref": "#/components/schemas/PydanticDateTimeSeries"
|
||||||
|
}
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
- **422**: Validation Error
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PUT /v1/measurement/value
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_value_put_v1_measurement_value_put), [swagger](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)
|
||||||
|
|
||||||
|
Fastapi Measurement Value Put
|
||||||
|
|
||||||
|
```
|
||||||
|
Merge the measurement of given key and value into EOS measurements at given datetime.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
|
||||||
|
- `datetime` (query, required): Datetime.
|
||||||
|
|
||||||
|
- `key` (query, required): Prediction key.
|
||||||
|
|
||||||
|
- `value` (query, required): No description provided.
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
- **422**: Validation Error
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PUT /v1/measurement/dataframe
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_dataframe_put_v1_measurement_dataframe_put), [swagger](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)
|
||||||
|
|
||||||
|
Fastapi Measurement Dataframe Put
|
||||||
|
|
||||||
|
```
|
||||||
|
Merge the measurement data given as dataframe into EOS measurements.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Request Body**:
|
||||||
|
|
||||||
|
- `application/json`: {
|
||||||
|
"$ref": "#/components/schemas/PydanticDateTimeDataFrame"
|
||||||
|
}
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
- **422**: Validation Error
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PUT /v1/measurement/data
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_measurement_data_put_v1_measurement_data_put), [swagger](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)
|
||||||
|
|
||||||
|
Fastapi Measurement Data Put
|
||||||
|
|
||||||
|
```
|
||||||
|
Merge the measurement data given as datetime data into EOS measurements.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Request Body**:
|
||||||
|
|
||||||
|
- `application/json`: {
|
||||||
|
"$ref": "#/components/schemas/PydanticDateTimeData"
|
||||||
|
}
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
- **422**: Validation Error
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## GET /v1/prediction/keys
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_keys_get_v1_prediction_keys_get), [swagger](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)
|
||||||
|
|
||||||
|
Fastapi Prediction Keys Get
|
||||||
|
|
||||||
|
```
|
||||||
|
Get a list of available prediction keys.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## GET /v1/prediction/series
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_series_get_v1_prediction_series_get), [swagger](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)
|
||||||
|
|
||||||
|
Fastapi Prediction Series Get
|
||||||
|
|
||||||
|
```
|
||||||
|
Get prediction for given key within given date range as series.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key (str): Prediction key
|
||||||
|
start_datetime (Optional[str]): Starting datetime (inclusive).
|
||||||
|
Defaults to start datetime of latest prediction.
|
||||||
|
end_datetime (Optional[str]: Ending datetime (exclusive).
|
||||||
|
Defaults to end datetime of latest prediction.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
|
||||||
|
- `key` (query, required): Prediction key.
|
||||||
|
|
||||||
|
- `start_datetime` (query, optional): Starting datetime (inclusive).
|
||||||
|
|
||||||
|
- `end_datetime` (query, optional): Ending datetime (exclusive).
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
- **422**: Validation Error
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## GET /v1/prediction/list
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_list_get_v1_prediction_list_get), [swagger](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)
|
||||||
|
|
||||||
|
Fastapi Prediction List Get
|
||||||
|
|
||||||
|
```
|
||||||
|
Get prediction for given key within given date range as value list.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key (str): Prediction key
|
||||||
|
start_datetime (Optional[str]): Starting datetime (inclusive).
|
||||||
|
Defaults to start datetime of latest prediction.
|
||||||
|
end_datetime (Optional[str]: Ending datetime (exclusive).
|
||||||
|
Defaults to end datetime of latest prediction.
|
||||||
|
interval (Optional[str]): Time duration for each interval.
|
||||||
|
Defaults to 1 hour.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
|
||||||
|
- `key` (query, required): Prediction key.
|
||||||
|
|
||||||
|
- `start_datetime` (query, optional): Starting datetime (inclusive).
|
||||||
|
|
||||||
|
- `end_datetime` (query, optional): Ending datetime (exclusive).
|
||||||
|
|
||||||
|
- `interval` (query, optional): Time duration for each interval.
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
- **422**: Validation Error
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## POST /v1/prediction/update
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_update_v1_prediction_update_post), [swagger](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)
|
||||||
|
|
||||||
|
Fastapi Prediction Update
|
||||||
|
|
||||||
|
```
|
||||||
|
Update predictions for all providers.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
force_update: Update data even if it is already cached.
|
||||||
|
Defaults to False.
|
||||||
|
force_enable: Update data even if provider is disabled.
|
||||||
|
Defaults to False.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
|
||||||
|
- `force_update` (query, optional): No description provided.
|
||||||
|
|
||||||
|
- `force_enable` (query, optional): No description provided.
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
- **422**: Validation Error
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## POST /v1/prediction/update/{provider_id}
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_prediction_update_provider_v1_prediction_update__provider_id__post), [swagger](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)
|
||||||
|
|
||||||
|
Fastapi Prediction Update Provider
|
||||||
|
|
||||||
|
```
|
||||||
|
Update predictions for given provider ID.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
provider_id: ID of provider to update.
|
||||||
|
force_update: Update data even if it is already cached.
|
||||||
|
Defaults to False.
|
||||||
|
force_enable: Update data even if provider is disabled.
|
||||||
|
Defaults to False.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
|
||||||
|
- `provider_id` (path, required): No description provided.
|
||||||
|
|
||||||
|
- `force_update` (query, optional): No description provided.
|
||||||
|
|
||||||
|
- `force_enable` (query, optional): No description provided.
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
- **422**: Validation Error
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## GET /strompreis
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_strompreis_strompreis_get), [swagger](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_strompreis_strompreis_get)
|
||||||
|
|
||||||
|
Fastapi Strompreis
|
||||||
|
|
||||||
|
```
|
||||||
|
Deprecated: Electricity Market Price Prediction per Wh (€/Wh).
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Set ElecPriceAkkudoktor as elecprice_provider, then update data with
|
||||||
|
'/v1/prediction/update'
|
||||||
|
and then request data with
|
||||||
|
'/v1/prediction/list?key=elecprice_marketprice_wh' or
|
||||||
|
'/v1/prediction/list?key=elecprice_marketprice_kwh' instead.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## POST /gesamtlast
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_gesamtlast_gesamtlast_post), [swagger](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_gesamtlast_gesamtlast_post)
|
||||||
|
|
||||||
|
Fastapi Gesamtlast
|
||||||
|
|
||||||
|
```
|
||||||
|
Deprecated: Total Load Prediction with adjustment.
|
||||||
|
|
||||||
|
Endpoint to handle total load prediction adjusted by latest measured data.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Use '/v1/prediction/list?key=load_mean_adjusted' instead.
|
||||||
|
Load energy meter readings to be added to EOS measurement by:
|
||||||
|
'/v1/measurement/load-mr/value/by-name' or
|
||||||
|
'/v1/measurement/value'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Request Body**:
|
||||||
|
|
||||||
|
- `application/json`: {
|
||||||
|
"$ref": "#/components/schemas/GesamtlastRequest"
|
||||||
|
}
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
- **422**: Validation Error
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## GET /gesamtlast_simple
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_gesamtlast_simple_gesamtlast_simple_get), [swagger](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_gesamtlast_simple_gesamtlast_simple_get)
|
||||||
|
|
||||||
|
Fastapi Gesamtlast Simple
|
||||||
|
|
||||||
|
```
|
||||||
|
Deprecated: Total Load Prediction.
|
||||||
|
|
||||||
|
Endpoint to handle total load prediction.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Set LoadAkkudoktor as load_provider, then update data with
|
||||||
|
'/v1/prediction/update'
|
||||||
|
and then request data with
|
||||||
|
'/v1/prediction/list?key=load_mean' instead.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
|
||||||
|
- `year_energy` (query, required): No description provided.
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
- **422**: Validation Error
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## GET /pvforecast
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_pvforecast_pvforecast_get), [swagger](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_pvforecast_pvforecast_get)
|
||||||
|
|
||||||
|
Fastapi Pvforecast
|
||||||
|
|
||||||
|
```
|
||||||
|
Deprecated: PV Forecast Prediction.
|
||||||
|
|
||||||
|
Endpoint to handle PV forecast prediction.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Set PVForecastAkkudoktor as pvforecast_provider, then update data with
|
||||||
|
'/v1/prediction/update'
|
||||||
|
and then request data with
|
||||||
|
'/v1/prediction/list?key=pvforecast_ac_power' and
|
||||||
|
'/v1/prediction/list?key=pvforecastakkudoktor_temp_air' instead.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## POST /optimize
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/fastapi_optimize_optimize_post), [swagger](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/fastapi_optimize_optimize_post)
|
||||||
|
|
||||||
|
Fastapi Optimize
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
|
||||||
|
- `start_hour` (query, optional): Defaults to current hour of the day.
|
||||||
|
|
||||||
|
**Request Body**:
|
||||||
|
|
||||||
|
- `application/json`: {
|
||||||
|
"$ref": "#/components/schemas/OptimizationParameters"
|
||||||
|
}
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
- **422**: Validation Error
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## GET /visualization_results.pdf
|
||||||
|
|
||||||
|
**Links**: [local](http://localhost:8503/docs#/default/get_pdf_visualization_results_pdf_get), [swagger](https://petstore3.swagger.io/?url=https://raw.githubusercontent.com/Akkudoktor-EOS/EOS/refs/heads/main/openapi.json#/default/get_pdf_visualization_results_pdf_get)
|
||||||
|
|
||||||
|
Get Pdf
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
- **200**: Successful Response
|
||||||
|
|
||||||
|
---
|
Loading…
x
Reference in New Issue
Block a user