mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-08-31 12:46:38 +00:00
Replace the single hourly "dishwasher" home appliance with a list of flexible consumers (home_appliances). Each consumer defines its load either as an explicit power profile (energy-preservingly resampled onto the optimization slot grid, incl. 15-min and non-integer interval ratios) or the flat consumption_wh/duration_h fallback, and runs ONCE or DAILY within its time windows and the optimization horizon. - ConsumerScheduleMode + shared load-definition validation (XOR of profile/fallback, reject negative/NaN/inf, unique device_id) - ApplianceGeneLayout: variable appliance gene block (index into allowed_start_slots), ONCE/DAILY calendar-day based, no snapping - per-device output: result.home_appliance_energy_wh, appliance_starts (absolute local times), per-device solution columns and DDBC RUN/OFF instructions on state transitions only - deprecate dishwasher/washingstart/Home_appliance_wh_per_hour with backward-compatible mapping and explicit conflict rejection - max_home_appliances is now an upper bound only; no demo appliance and no on/off behaviour - docs, openapi.json, CHANGELOG and optimize_result_2* fixtures updated; new tests/test_homeappliance.py covers the mandatory test matrix Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
283 lines
12 KiB
Markdown
283 lines
12 KiB
Markdown
% SPDX-License-Identifier: Apache-2.0
|
||
(resource-page)=
|
||
|
||
# Resources (Device Simulations)
|
||
|
||
## Concepts
|
||
|
||
The simulations for resources are leaning on general concepts of the [S2 standard].
|
||
|
||
### Control Types
|
||
|
||
The control of resources and such what a resource simulation will simulate follows three
|
||
basic control principles:
|
||
|
||
- Operation Mode Based Control (OMBC)
|
||
- Fill Rate Based Control (FRBC)
|
||
- Demand Driven Based Control (DDBC)
|
||
|
||
Although these control principles differ enough to separate them into three distinct control types,
|
||
there are some common aspects that make them similar:
|
||
|
||
- Operation Modes
|
||
- Transitions and
|
||
- Timers.
|
||
|
||
The objective for a control type is under which circumstances what things can be adjusted, and what
|
||
the constraints are for these adjustments. The three control types model a virtual, abstract resource
|
||
for simulation.
|
||
|
||
The abstract resource ignores all details of pyhsical device that are not relevant to energy
|
||
management. In addition, physical devices have an enormous variety in parameters, sensors, control
|
||
strategies, concerns, safeguards, and so on. It would be practically impossible to develop a
|
||
simulation that can
|
||
understand all the parameters of all the physical devices on the market. By making the resource more
|
||
abstract, its concepts can be translated to all sorts of physical devices, even though internally
|
||
they function very differently. As a consequence, it not always possible to make a 100% accurate
|
||
description of all the behaviors and constraints in these abstractions. But the abstractions used
|
||
in the control types are quite powerful, and should allow you to come pretty close.
|
||
|
||
The control types basically define how the simulated resource can be described. The user in the end
|
||
selects the proper desciption of a physical device using the configuration options provided for
|
||
resource simulations. The configuration sets how the simulated resource functions, what it can do and
|
||
what kind of constraints it has.
|
||
|
||
### Resource Simulation
|
||
|
||
Based on the description of this virtual resource, the resource simulation can make predictions of
|
||
what the physical device will do in certain situations, and when it is allowed to execute
|
||
instructions generated by the optimization as part of the energy management plan evaluation.
|
||
|
||
### Resource Status
|
||
|
||
Once the physical device has changed it's behavior, the resource simulation should be informed
|
||
to make the simulation change it's state accordingly.
|
||
|
||
The actual state of a pyhsical device may be reported to the resource simulation by the
|
||
**PUT** `/v1/resource/status` API endpoint.
|
||
|
||
## Battery
|
||
|
||
There is a wealth of possible battery operation modes:
|
||
|
||
<!-- pyml disable line-length -->
|
||
| Mode | Purpose / Behavior | Typical Trigger / Context |
|
||
| ------------------------- | --------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
|
||
| **IDLE** | Battery neither charges nor discharges (SOC stable). | No active control objective or power imbalance below thresholds. |
|
||
| **SELF_CONSUMPTION** | Charge from PV surplus and discharge to cover local load. | PV generation > load (charge) or load > PV (discharge). |
|
||
| **NON_EXPORT** | Charge from on-site or local surplus with the goal of minimizing or preventing energy export to the external grid. Discharging to the grid is not allowed. | Export limit reached and SOC < SOC_max. |
|
||
| **PEAK_SHAVING** | Discharge to keep grid import below a target threshold. | Predicted or measured site load exceeds peak limit. |
|
||
| **GRID_SUPPORT_EXPORT** | Discharge energy to grid for revenue (V2G, wholesale market, flexibility service). | Market or signal permits profitable export. |
|
||
| **GRID_SUPPORT_IMPORT** | Charge from grid to absorb surplus or provide up-regulation service. | Low-price or grid-support signal detected. |
|
||
| **FREQUENCY_REGULATION** | Rapid charge/discharge response to grid frequency deviations. | Active participation in frequency control. |
|
||
| **RAMP_RATE_CONTROL** | Smooth site-level power ramp rates by buffering fluctuations. | Sudden PV/load change exceeding ramp limit. |
|
||
| **RESERVE_BACKUP** | Maintain SOC ≥ reserve threshold to ensure backup capacity. | Resilience mode active, grid operational. |
|
||
| **OUTAGE_SUPPLY** | Islanded operation: power local loads using stored energy (and PV if available). | Grid failure detected. |
|
||
| **FORCED_CHARGE** | Manual or external control command to charge (e.g., pre-event, maintenance). No discharge. | Operator or optimizer command. |
|
||
| **FORCED_DISCHARGE** | Manual or external control command to discharge. No charge. | Operator or optimizer command. |
|
||
| **FAULT** | Battery unavailable due to fault, safety, or protection state. | Fault detected (thermal, voltage, comms, etc.). |
|
||
<!-- pyml enable line-length -->
|
||
|
||
The optimization algorithm, the device simulation and the configuration properties only support the
|
||
most important of these modes.
|
||
|
||
### Battery Simulation
|
||
|
||
The battery simulation assumes an idealized battery model. Under this model, the battery can be
|
||
operated in three discrete operation modes with fill rate based control (FRBC):
|
||
|
||
| **Operation Mode ID** | **Description** |
|
||
| ------------------------ | --------------------------------------------------------------------- |
|
||
| **SELF_CONSUMPTION** | Charge from local surplus and discharge to cover local load. |
|
||
| **NON_EXPORT** | Charge from local surplus and do not discharge. |
|
||
| **FORCED_CHARGE** | Charge. |
|
||
|
||
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.
|
||
|
||
The **fill level** (0.0–1.0) specifies the normalized fill level relative to the
|
||
battery's nominal maximum charge. A value of 1.0 corresponds to full while 0.0 indicates empty.
|
||
Intermediate values scale the fill level proportionally.
|
||
|
||
### Battery Configuration
|
||
|
||
### Battery Stati
|
||
|
||
To keep the battery simulation in synchonization with the actual stati of the battery the following
|
||
resource stati may be reported to EOS by the **PUT** `/v1/resource/status` API endpoint.
|
||
|
||
#### Battery FRBCActuatorStatus
|
||
|
||
The operation mode the battery is currently operated.
|
||
|
||
```json
|
||
{
|
||
"type": "FRBCActuatorStatus",
|
||
"active_operation_mode_id": "GRID_SUPPORT_IMPORT",
|
||
"operation_mode_factor": "0.375",
|
||
"previous_operation_mode_id": "SELF_CONSUMPTION",
|
||
"transistion_timestamp": "20250725T12:00:12"
|
||
}
|
||
```
|
||
|
||
#### Battery FRBCStorageStatus
|
||
|
||
The current battery state of charge (SoC).
|
||
|
||
```json
|
||
{
|
||
"type": "FRBCStorageStatus",
|
||
"present_fill_level": "0.88"
|
||
}
|
||
```
|
||
|
||
#### Battery PowerMeasurement
|
||
|
||
The current power that the battery is charged or discharged with \[W\].
|
||
|
||
```json
|
||
{
|
||
"type": "PowerMeasurement",
|
||
"measurement_timestamp": "20250725T12:00:12",
|
||
"values": [
|
||
{
|
||
"commodity_quantity": "ELECTRIC.POWER.L1",
|
||
"value": "887.5"
|
||
},
|
||
{
|
||
"commodity_quantity": "ELECTRIC.POWER.L2",
|
||
"value": "905.5"
|
||
},
|
||
{
|
||
"commodity_quantity": "ELECTRIC.POWER.L2",
|
||
"value": "1100.7"
|
||
},
|
||
]
|
||
}
|
||
```
|
||
|
||
For symmetric (or unknown) power distribution:
|
||
|
||
```json
|
||
{
|
||
"type": "PowerMeasurement",
|
||
"measurement_timestamp": "20250725T12:00:12",
|
||
"values": [
|
||
{
|
||
"commodity_quantity": "ELECTRIC.POWER.3_PHASE_SYM",
|
||
"value": "1000"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
## Electric Vehicle
|
||
|
||
The electric vehicle is basically a battery with a reduced set of operation modes.
|
||
|
||
### 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. |
|
||
| **FORCED_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
|
||
|
||
The optimization algorithm schedules any number of flexible consumers (home appliances). Each
|
||
consumer has a unique `device_id` and is scheduled independently. The `schedule_mode` selects how
|
||
often a consumer runs:
|
||
|
||
- `ONCE` — a single run somewhere within the optimization horizon ("fire and forget").
|
||
- `DAILY` — one run per local calendar day that still has a feasible complete run.
|
||
|
||
### Home Appliance Simulation
|
||
|
||
Each consumer's load is described by the energy of a single complete run, resampled onto the
|
||
optimization slot grid (hourly or 15-minute). Multiple consumers and multiple daily runs may
|
||
overlap; their energy adds up.
|
||
|
||
### Home Appliance Configuration
|
||
|
||
A consumer's load is defined **either** by an explicit power profile or by the flat
|
||
`consumption_wh` + `duration_h` fallback (exactly one of the two).
|
||
|
||
Two consumers, one defined by the flat fallback (runs once), one by an explicit 15-minute power
|
||
profile that runs once per day:
|
||
|
||
```json
|
||
[
|
||
{
|
||
"device_id": "dishwasher1",
|
||
"consumption_wh": 2000,
|
||
"duration_h": 3,
|
||
"schedule_mode": "ONCE"
|
||
},
|
||
{
|
||
"device_id": "washingmachine1",
|
||
"load_profile_power_w": [200, 2000, 1800, 100],
|
||
"load_profile_interval_seconds": 900,
|
||
"schedule_mode": "DAILY"
|
||
}
|
||
]
|
||
```
|
||
|
||
- `load_profile_power_w`: non-negative power values in watts describing one complete run. Each value
|
||
covers `load_profile_interval_seconds` (default: the configured optimization interval). The profile
|
||
is resampled energy-preservingly onto the optimization slot grid.
|
||
- `consumption_wh` / `duration_h`: flat fallback used when no `load_profile_power_w` is given.
|
||
|
||
A consumer may be restricted to run within a time window of 5 hours starting at 8:00 every day and
|
||
another time window of 3 hours starting at 15:00 every day. The complete run must fit inside a
|
||
single window. See [Time Window Sequence Configuration](configtimewindow-page) for more information.
|
||
|
||
```json
|
||
[
|
||
{
|
||
"device_id": "dishwasher1",
|
||
"consumption_wh": 2000,
|
||
"duration_h": 3,
|
||
"time_windows": {
|
||
"windows": [
|
||
{
|
||
"start_time": "08:00",
|
||
"duration": "5 hours"
|
||
},
|
||
{
|
||
"start_time": "15:00",
|
||
"duration": "3 hours"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
]
|
||
```
|
||
|
||
:::{admonition} Note
|
||
:class: note
|
||
A `ONCE` consumer without any valid start (given its time windows and the horizon) is rejected. For
|
||
`DAILY`, a calendar day without a feasible run simply gets no run for that day.
|
||
:::
|
||
|
||
### 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. |
|
||
| **OFF** | The home appliance does not run. |
|
||
|
||
The **operation mode factor** (0.0–1.0) is ignored.
|