feat(optimization): schedule any number of flexible consumers

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>
This commit is contained in:
Andreas
2026-07-15 14:19:46 +02:00
co-authored by Claude Opus 4.8
parent c59bf1b486
commit 67cf6f7d8a
21 changed files with 2505 additions and 1094 deletions
+33 -9
View File
@@ -193,28 +193,52 @@ indicates no power transfer. Intermediate values scale the power proportionally.
## Home Appliance
The optimization algorithm supports one start of the home appliance within the optimization
horizon.
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
Home appliance to run within the optimization horizon.
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
"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"
}
]
```
Home appliance 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. See
[Time Window Sequence Configuration](configtimewindow-page) for more information.
- `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
[
@@ -240,8 +264,8 @@ window of 3 hours starting at 15:00 every day. See
:::{admonition} Note
:class: note
The optimization algorithm always restricts to one start within the optimization horizon per
energy management run.
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