Files
EOS/docs/akkudoktoreos/optimauto.md

449 lines
16 KiB
Markdown
Raw Normal View History

fix: automatic optimization (#596) This fix implements the long term goal to have the EOS server run optimization (or energy management) on regular intervals automatically. Thus clients can request the current energy management plan at any time and it is updated on regular intervals without interaction by the client. This fix started out to "only" make automatic optimization (or energy management) runs working. It turned out there are several endpoints that in some way update predictions or run the optimization. To lock against such concurrent attempts the code had to be refactored to allow control of execution. During refactoring it became clear that some classes and files are named without a proper reference to their usage. Thus not only refactoring but also renaming became necessary. The names are still not the best, but I hope they are more intuitive. The fix includes several bug fixes that are not directly related to the automatic optimization but are necessary to keep EOS running properly to do the automatic optimization and to test and document the changes. This is a breaking change as the configuration structure changed once again and the server API was also enhanced and streamlined. The server API that is used by Andreas and Jörg in their videos has not changed. * fix: automatic optimization Allow optimization to automatically run on configured intervals gathering all optimization parameters from configuration and predictions. The automatic run can be configured to only run prediction updates skipping the optimization. Extend documentaion to also cover automatic optimization. Lock automatic runs against runs initiated by the /optimize or other endpoints. Provide new endpoints to retrieve the energy management plan and the genetic solution of the latest automatic optimization run. Offload energy management to thread pool executor to keep the app more responsive during the CPU heavy optimization run. * fix: EOS servers recognize environment variables on startup Force initialisation of EOS configuration on server startup to assure all sources of EOS configuration are properly set up and read. Adapt server tests and configuration tests to also test for environment variable configuration. * fix: Remove 0.0.0.0 to localhost translation under Windows EOS imposed a 0.0.0.0 to localhost translation under Windows for convenience. This caused some trouble in user configurations. Now, as the default IP address configuration is 127.0.0.1, the user is responsible for to set up the correct Windows compliant IP address. * fix: allow names for hosts additional to IP addresses * fix: access pydantic model fields by class Access by instance is deprecated. * fix: down sampling key_to_array * fix: make cache clear endpoint clear all cache files Make /v1/admin/cache/clear clear all cache files. Before it only cleared expired cache files by default. Add new endpoint /v1/admin/clear-expired to only clear expired cache files. * fix: timezonefinder returns Europe/Paris instead of Europe/Berlin timezonefinder 8.10 got more inaccurate for timezones in europe as there is a common timezone. Use new package tzfpy instead which is still returning Europe/Berlin if you are in Germany. tzfpy also claims to be faster than timezonefinder. * fix: provider settings configuration Provider configuration used to be a union holding the settings for several providers. Pydantic union handling does not always find the correct type for a provider setting. This led to exceptions in specific configurations. Now provider settings are explicit comfiguration items for each possible provider. This is a breaking change as the configuration structure was changed. * fix: ClearOutside weather prediction irradiance calculation Pvlib needs a pandas time index. Convert time index. * fix: test config file priority Do not use config_eos fixture as this fixture already creates a config file. * fix: optimization sample request documentation Provide all data in documentation of optimization sample request. * fix: gitlint blocking pip dependency resolution Replace gitlint by commitizen. Gitlint is not actively maintained anymore. Gitlint dependencies blocked pip from dependency resolution. * fix: sync pre-commit config to actual dependency requirements .pre-commit-config.yaml was out of sync, also requirements-dev.txt. * fix: missing babel in requirements.txt Add babel to requirements.txt * feat: setup default device configuration for automatic optimization In case the parameters for automatic optimization are not fully defined a default configuration is setup to allow the automatic energy management run. The default configuration may help the user to correctly define the device configuration. * feat: allow configuration of genetic algorithm parameters The genetic algorithm parameters for number of individuals, number of generations, the seed and penalty function parameters are now avaliable as configuration options. * feat: allow configuration of home appliance time windows The time windows a home appliance is allowed to run are now configurable by the configuration (for /v1 API) and also by the home appliance parameters (for the classic /optimize API). If there is no such configuration the time window defaults to optimization hours, which was the standard before the change. Documentation on how to configure time windows is added. * feat: standardize mesaurement keys for battery/ ev SoC measurements The standardized measurement keys to report battery SoC to the device simulations can now be retrieved from the device configuration as a read-only config option. * feat: feed in tariff prediction Add feed in tarif predictions needed for automatic optimization. The feed in tariff can be retrieved as fixed feed in tarif or can be imported. Also add tests for the different feed in tariff providers. Extend documentation to cover the feed in tariff providers. * feat: add energy management plan based on S2 standard instructions EOS can generate an energy management plan as a list of simple instructions. May be retrieved by the /v1/energy-management/plan endpoint. The instructions loosely follow the S2 energy management standard. * feat: make measurement keys configurable by EOS configuration. The fixed measurement keys are replaced by configurable measurement keys. * feat: make pendulum DateTime, Date, Duration types usable for pydantic models Use pydantic_extra_types.pendulum_dt to get pydantic pendulum types. Types are added to the datetimeutil utility. Remove custom made pendulum adaptations from EOS pydantic module. Make EOS modules use the pydantic pendulum types managed by the datetimeutil module instead of the core pendulum types. * feat: Add Time, TimeWindow, TimeWindowSequence and to_time to datetimeutil. The time windows are are added to support home appliance time window configuration. All time classes are also pydantic models. Time is the base class for time definition derived from pendulum.Time. * feat: Extend DataRecord by configurable field like data. Configurable field like data was added to support the configuration of measurement records. * feat: Add additional information to health information Version information is added to the health endpoints of eos and eosDash. The start time of the last optimization and the latest run time of the energy management is added to the EOS health information. * feat: add pydantic merge model tests * feat: add plan tab to EOSdash The plan tab displays the current energy management instructions. * feat: add predictions tab to EOSdash The predictions tab displays the current predictions. * feat: add cache management to EOSdash admin tab The admin tab is extended by a section for cache management. It allows to clear the cache. * feat: add about tab to EOSdash The about tab resembles the former hello tab and provides extra information. * feat: Adapt changelog and prepare for release management Release management using commitizen is added. The changelog file is adapted and teh changelog and a description for release management is added in the documentation. * feat(doc): Improve install and devlopment documentation Provide a more concise installation description in Readme.md and add extra installation page and development page to documentation. * chore: Use memory cache for interpolation instead of dict in inverter Decorate calculate_self_consumption() with @cachemethod_until_update to cache results in memory during an energy management/ optimization run. Replacement of dict type caching in inverter is now possible because all optimization runs are properly locked and the memory cache CacheUntilUpdateStore is properly cleared at the start of any energy management/ optimization operation. * chore: refactor genetic Refactor the genetic algorithm modules for enhanced module structure and better readability. Removed unnecessary and overcomplex devices singleton. Also split devices configuration from genetic algorithm parameters to allow further development independently from genetic algorithm parameter format. Move charge rates configuration for electric vehicles from optimization to devices configuration to allow to have different charge rates for different cars in the future. * chore: Rename memory cache to CacheEnergyManagementStore The name better resembles the task of the cache to chache function and method results for an energy management run. Also the decorator functions are renamed accordingly: cachemethod_energy_management, cache_energy_management * chore: use class properties for config/ems/prediction mixin classes * chore: skip debug logs from mathplotlib Mathplotlib is very noisy in debug mode. * chore: automatically sync bokeh js to bokeh python package bokeh was updated to 3.8.0, make JS CDN automatically follow the package version. * chore: rename hello.py to about.py Make hello.py the adapted EOSdash about page. * chore: remove demo page from EOSdash As no the plan and prediction pages are working without configuration, the demo page is no longer necessary * chore: split test_server.py for system test Split test_server.py to create explicit test_system.py for system tests. * chore: move doc utils to generate_config_md.py The doc utils are only used in scripts/generate_config_md.py. Move it there to attribute for strong cohesion. * chore: improve pydantic merge model documentation * chore: remove pendulum warning from readme * chore: remove GitHub discussions from contributing documentation Github discussions is to be replaced by Akkudoktor.net. * chore(release): bump version to 0.1.0+dev for development * build(deps): bump fastapi[standard] from 0.115.14 to 0.117.1 bump fastapi and make coverage version (for pytest-cov) explicit to avoid pip break. * build(deps): bump uvicorn from 0.36.0 to 0.37.0 BREAKING CHANGE: EOS configuration changed. V1 API changed. - The available_charge_rates_percent configuration is removed from optimization. Use the new charge_rate configuration for the electric vehicle - Optimization configuration parameter hours renamed to horizon_hours - Device configuration now has to provide the number of devices and device properties per device. - Specific prediction provider configuration to be provided by explicit configuration item (no union for all providers). - Measurement keys to be provided as a list. - New feed in tariff providers have to be configured. - /v1/measurement/loadxxx endpoints are removed. Use generic mesaurement endpoints. - /v1/admin/cache/clear now clears all cache files. Use /v1/admin/cache/clear-expired to only clear all expired cache files. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
2025-10-28 02:50:31 +01:00
% SPDX-License-Identifier: Apache-2.0
# Automatic Optimization
## Introduction
EOS offers two approaches to optimize your energy management system: `post /optimize optimization` and
`automatic optimization`.
The `post /optimize optimization` interface, based on a **POST** request to `/optimize`, is widely
used. It was originally developed by Andreas at the start of the project and is still demonstrated
in his instructional videos. This interface allows users or external systems to trigger an
optimization manually, supplying custom parameters and timing.
As an alternative, EOS supports `automatic optimization`, which runs automatically at configured
intervals. It retrieves all required input data — including electricity prices, battery storage
capacity, PV production forecasts, and temperature data — based on your system configuration.
### Genetic Algorithm
Both optimization modes use the same core optimization engine.
EOS uses a [genetic algorithm](https://en.wikipedia.org/wiki/Genetic_algorithm) to find an optimal
control strategy for home energy devices such as household loads, batteries, and electric vehicles.
In this context, each **individual** represents a possible solution — a specific control schedule
that defines how devices should operate over time. These individuals are evaluated using
[resource simulations](#resource-page), which model the systems energy behavior over a defined time
period divided into fixed intervals.
The quality of each solution (its *fitness*) is determined by how well it performs during
simulation, based on objectives such as minimizing electricity costs, maximizing self-consumption,
or meeting battery charge targets.
Through an iterative process of selection, crossover, and mutation, the algorithm gradually evolves
more effective solutions. The final result is an optimized control strategy that balances multiple
system goals within the constraints of the input data and configuration.
:::{note}
You dont need to understand the internal workings of the genetic algorithm to benefit from
automatic optimization. EOS handles everything behind the scenes based on your configuration.
However, advanced users can fine-tune the optimization behavior using additional settings like
population size, penalties, and random seed.
:::
## Energy Management Plan
Whenever the optimization is run, the energy management plan is updated. The energy management plan
provides a list of energy management instructions in chronological order. The instructions lean on
to the [S2 standard](https://docs.s2standard.org/) to have maximum flexibility and stay completely
independent from any manufacturer.
### Battery Instructions
The battery control instructions assume an idealized battery model. Under this model, the battery
can be operated in four discrete operation modes:
| **Operation Mode ID** | **Description** |
| --------------------- | ------------------------------------------------------------------------------------ |
| **IDLE** | Battery neither charges nor discharges; holds its state of charge. |
| **CHARGE** | Charge at a specified power rate up to the allowable maximum. |
| **DISCHARGE** | Discharge at a specified power rate up to the allowable maximum. |
| **ALLOW_DISCHARGE** | Allow the battery to freely discharge depending on its instantaneous power setpoint. |
The **operation mode factor** (0.01.0) specifies the normalized power rate relative to the
battery's nominal maximum charge or discharge power. A value of 1.0 corresponds to full-rate
charging or discharging, while 0.0 indicates no power transfer. Intermediate values scale the power
proportionally.
### Electric Vehicle Instructions
The electric vehicle control instructions assume an idealized EV battery model. Under this model,
the EV battery can be operated in two operation modes:
| **Operation Mode ID** | **Description** |
| --------------------- | ------------------------------------------------------------------------------------ |
| **IDLE** | Battery neither charges nor discharges; holds its state of charge. |
| **CHARGE** | Charge at a specified power rate up to the allowable maximum. |
The **operation mode factor** (0.01.0) specifies the normalized power rate relative to the
battery's nominal maximum charge power. A value of 1.0 corresponds to full-rate charging, while 0.0
indicates no power transfer. Intermediate values scale the power proportionally.
### Home Appliance Instructions
The home appliance instructions assume an idealized home appliance model. Under this model,
the home appliance can be operated in two operation modes:
| **Operation Mode ID** | **Description** |
| --------------------- | ------------------------------------------------------------------------------------ |
| **RUN** | The home appliance is started and runs until the end of it's power sequence. |
| **IDLE** | The home appliance does not run. |
The **operation mode factor** (0.01.0) is ignored.
## Configuration
### Energy management configuration
The energy management is run on configured intervals with some startup delay after server start.
Both values are given in seconds.
:::{admonition} Note
:class: note
If no interval is configured (`None`, `null`) there will be only one energy management run at
startup.
:::
The energy management can be run in two modes:
- **OPTIMIZATION**: A full optimization is done. This includes update of predictions.
- **PREDICTION**: Only the predictions are updated.
**Example:**
```json
{
"ems": {
"startup_delay": 5.0,
"interval": 300.0,
"mode": "OPTIMIZATION"
}
}
```
### Optimization Configuration
#### Optimization Time Configuration
- **horizon_hours**:
The optimization horizon parameter defines the default time window — in hours — within which
the energy optimization goal shall be achieved.
Specific devices, like the home appliance, have their own configuration for time windows. If
the time windows are not configured the simulation uses the default time window.
Each device simulation run must ensure that all tasks or appliance cycles (e.g., running a
dishwasher) are completed within the configured time windows.
- **interval**: Defines the time step in seconds between control actions
(e.g. `3600` for one hour, `900` for 15 minutes).
:::{warning}
**Current Limitation**
At present, the `interval` setting is **not used** by the genetic algorithm. Instead:
- The control interval is fixed to **1 hour**.
Support for configurable intervals (e.g. 15-minute steps) may be added in a future release.
:::
#### Genetic Algorithm Parameters
The behavior of the genetic algorithm can be customized using the following configuration options:
- **individuals** (`int`, default: `300`):
Sets the number of individuals (candidate solutions) in the (first) generation. A higher number
increases solution diversity and the chance of finding a good result, but also increases
computation time.
- **generations** (`int`, default: `400`):
Sets the number of generations to evaluate the optimal solution. In each generation, solutions are
evaluated and evolved. More generations can improve optimization quality but increase computation
time. Best results are usually found within a moderate number of generations.
- **seed** (`int` or `null`, default: `null`):
Sets the random seed for reproducible results.
- If `null`, a random seed is used (non-reproducible).
- If an integer is provided, it ensures that the same optimization input yields the same output.
A fixed seed to ensure reproducibility. Runs with the same seed and configuration will
produce the same results.
- **penalties** (`dict`):
Defines how penalties are applied to solutions that violate constraints (e.g., undercharged
batteries). Penalty function parameter values influence the fitness score, discouraging
undesirable solutions.
:::{note}
**Supported Penalty Functions**
Currently, the only supported penalty function parameter is:
- `ev_soc_miss`:
Applies a penalty when the **state of charge (SOC)** of the electric vehicle battery falls below
the required minimum. This encourages the optimizer to ensure sufficient EV charging.
:::
#### Value Formats
- **Time-related values**:
- `hours`: specified in **hours** (e.g. `24`)
- `interval`: specified in **seconds** (e.g. `3600`)
- **Genetic algorithm parameters**:
- `individuals`: must be an **integer**
- `seed`: must be an **integer** or `null` for random behavior
- **Penalty function parameter values**: may be `float`, `int`, or `string`, depending on the type
of penalty function.
#### Optimization configuration example
```json
{
"optimization": {
"hours": 24,
"interval": 3600,
"genetic" : {
"individuals": 300,
"generations": 400,
"seed": null,
"penalties": {
"ev_soc_miss": 10
}
}
}
}
```
### Device simulation configuration
The device simulations are used to evaluate the fitness of the individuals of the solution
population.
The GENETIC algorithm supports 4 devices:
- **inverter**: A photovoltaic power inverter that can export to the grid and charge a battery.
The inverter is mandatory.
- **electric_vehicle**: An electric vehicle, basically the battery of an electric vehicle. The
The electrical vehicle is optional.
- **battery**: A battery that can be charged by the inverter. The battery is mandatory.
- **home_appliance**: A home appliance, like a washing machine or a dish washer. The home
appliance is optional.
:::{admonition} Warning
:class: warning
The GENETIC algorithm can only use the first inverter, electrical vehicle, battery, home appliance
that is configured, even if more devices are configured.
:::
#### Inverter simulation configuration
**Example:**
```json
{
"devices": {
"max_inverters": 1,
"inverters": [
{
"device_id": "inv1",
"max_power_w": 10000,
"battery_id": "bat1"
}
]
}
}
```
#### Electric vehicle simulation configuration
**Example:**
```json
{
"devices": {
"max_electric_vehicles": 1,
"electric_vehicles": [
{
"device_id": "ev1",
"capacity_wh": 50000,
"max_charge_power_w": 10000,
"charge_rates": [0.0, 0.25, 0.5, 0.75, 1.0],
"min_soc_percentage": 10,
"max_soc_percentage": 80
}
]
},
"measurement": {
"electric_vehicle_soc_keys": ["ev1_soc"]
}
}
```
#### Battery simulation configuration
**Example:**
```json
{
"devices": {
"max_batteries": 1,
"batteries": [
{
"device_id": "battery1",
"capacity_wh": 8000,
"charging_efficiency": 0.88,
"discharging_efficiency": 0.88,
"levelized_cost_of_storage_kwh": 0.12,
"max_charge_power_w": 8000,
"min_charge_power_w": 50,
"charge_rates": null,
"min_soc_percentage": 5,
"max_soc_percentage": 95
}
]
}
}
```
#### Home appliance simulation configuration
**Example:**
```json
{
"devices": {
"max_home_appliances": 1,
"home_appliances": [
{
"device_id": "washing machine",
"consumption_wh": 600,
"duration_h": 3,
"time_windows": null,
}
]
}
}
```
The time windows the home appliance may run can be [configured](#configtimewindow-page) in several
ways. See the [time window configuration](#configtimewindow-page) for details.
## Predictions configuration
The device simulation may rely on predictions to simulate proper behaviour. E.g. the inverter needs
to know the PV forecast.
Configure the [predictions](#prediction-page) as described on the [prediction page](#prediction-page).
### Providing your own prediction data
If EOS does not have a suitable prediction provider you can provide your own data for a prediction.
Configure the respective import provider (ElecPriceImport, LoadImport, PVForecastImport,
WeatherImport) and use one of the following endpoints to provide your own data:
- **PUT** `/v1/prediction/import/ElecPriceImport`
- **PUT** `/v1/prediction/import/LoadImport`
- **PUT** `/v1/prediction/import/PVForecastImport`
- **PUT** `/v1/prediction/import/WeatherImport`
## Measurement configuration
Predictions and device simulations often rely on **measurement data** to produce accurate results.
For example:
- A **load forecast** requires past energy meter readings.
- A **battery simulation** needs the current **state of charge (SoC)** to start from the correct
condition.
Before using these features, make sure to configure the [measurement](#measurement-page) as
described on the [measurement page](#measurement-page).
### Providing your own measurement data
You can provide your own measurement data to the prediction and simulation engine through the
following REST endpoints (see the [measurement page](#measurement-page) for details on the data
format):
- **PUT** `/v1/measurement/data`
- **PUT** `/v1/measurement/dataframe`
- **PUT** `/v1/measurement/series`
- **PUT** `/v1/measurement/value`
### Example: Supplying Battery and EV SoC
For **batteries** and **electric vehicles**, it is strongly recommended to provide
**current SoC**. This ensures that simulations start with the correct state.
The simplest way is to use the `/v1/measurement/value` endpoint.
Assuming the battery is named `battery1` and the EV is named `ev11`:
1. **Use the measurement keys** that are pre-configured for your **devices**. For example:
```json
{
"devices": {
"batteries": [
{
"device_id": "battery1", "capacity_wh": 8000, ...
"measurement_key_soc_factor": "battery1-soc-factor", ...
}
],
"electric_vehicles": [
{
"device_id": "ev11", "capacity_wh": 8000, ...
"measurement_key_soc_factor": "ev11-soc-factor", ...
}
]
}
}
```
2. **Record your SoC readings** to these keys.
- Enter the values as **factor of total capacity** of the respective **battery**.
In these examples:
- datetime specifies the timestamp of the measurement.
- key is the measurement key (e.g. battery1-soc-factor).
- value is the numeric measurement value (e.g. SoC as factor of total capacity).
#### Raw HTTP request
```http
PUT http://127.0.0.1:8503/v1/measurement/value?datetime=2025-09-26T16%3A39&key=battery1-soc-factor&value=0.57
PUT http://127.0.0.1:8503/v1/measurement/value?datetime=2025-09-26T16%3A39&key=ev11-soc-factor&value=0.22
```
#### Equivalent curl commands
```bash
curl -X PUT "http://127.0.0.1:8503/v1/measurement/value?datetime=2025-09-26T16%3A39&key=battery1-soc-factor&value=0.57"
curl -X PUT "http://127.0.0.1:8503/v1/measurement/value?datetime=2025-09-26T16%3A39&key=ev11-soc-factor&value=0.22"
```
### Example: Supplying Load Data
To provide your actual load measurements in Akkudoktor-EOS:
1. **Configure the measurement keys** for your load energy meters. For example:
```json
{
"measurements": {
"load_emr_keys": ["my_load_meter_reading", "my_other_load_meter_reading"]
}
}
```
2. **Record your meter readings** to these keys.
- Enter the values exactly as your energy meters report them, in **kWh**.
- Use the same approach as when supplying battery or EV SoC data.