mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2025-10-29 13:56:21 +00:00
449 lines
16 KiB
Markdown
449 lines
16 KiB
Markdown
|
|
% 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 system’s 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 don’t 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.0–1.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.0–1.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.0–1.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.
|