The energy still stored when the horizon ends keeps its worth: it replaces
grid imports that are paid for afterwards. Crediting that with a single
price per kWh cannot describe it, because the value is not linear in the
amount stored. The first kWh replaces the most expensive hour that PV
cannot cover, the next one the second most expensive, and once every such
hour is served, further energy replaces nothing.
A scalar has to pick one slope for all of it. High enough for the first kWh
means hoarding a full battery; low enough for the last kWh means running it
empty by the end of the horizon - which is exactly what the previous default
of 0 EUR/kWh did.
terminal_value_mode = AUTO (the new default) builds the curve instead. There
is no forecast beyond the horizon, so its trailing window stands in for the
day that follows: residual load max(load - PV, 0) per slot, priced at its
import price, sorted and accumulated. LCOS is subtracted from every marginal
value so stored energy is not credited twice, and the tail beyond the
residual load is only credited when direct marketing allows an export. The
curve is built once per run; the search only interpolates on it.
The solution reports what a run used as terminal_value, curve included, so
the shape can be inspected instead of guessed. FIXED restores the previous
scalar behaviour.
In a 48 h scenario with two cheap slots at the end, AUTO keeps the battery
at 50 % and credits 3.85 EUR where FIXED with 0 EUR/kWh drains it to empty.
The stored optimization results move accordingly - the objective changed.
The genetic optimizer was hard-wired to an hourly grid and forced
optimization.interval to 3600 s. Generalize it to a configurable slot grid
of length prediction.hours * (3600 / interval), accepting 900 (15 min) in
addition to the default 3600 (1 hour) so the optimizer can schedule on a
quarter-hour grid for 15-minute dynamic electricity tariffs.
- genetic.py: slot_duration_h / slots_per_hour / total_slots helpers; all GA
vectors sized by total_slots; simulate()/evaluate() indexed by start slot.
- geneticparams.py: allow {900, 3600}; scale the load power series to per-slot
energy, mirroring the PV series.
- battery.py / inverter.py: scale power caps to per-slot energy caps via
slot_duration_h; homeappliance.py carries the hook.
- geneticsolution.py: serialize solution and plan on the slot grid (interval
freq, start-slot offset, second-based instruction instants).
The default 3600 s interval keeps the previous hourly behaviour; the genetic
regression suite is unchanged. Adds tests for the 15-minute slot grid.
Fix documentation for the loadforecast_power_w key.
Fix documentation to explain the usage of import file/ JSON string to
primarily initialise prediction data.
Fix code scanning alert no. 6: URL redirection from remote source
Enable to automatically save the configuration to the configuration file
by default, which is a widespread user expectation.
Make the genetic parameters non optional for better pydantic compliance.
Update:
- bump pytest to 9.0.3
- bump pillow to 12.2.0
- bump platformdirs to 4.9.6
- bump typespyyaml to 6.0.12.20260408
- bump tzfpy to 1.2.0
- bump pydantic to 2.13.0
- bump types-requests to 2.33.0.20260408
Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
Co-authored-by: Normann <github@koldrack.com>
Validate solution prediction data before processing.
If required prediction data is missing, the prediction is skipped
instead of raising an exception.
Introduce a new configuration file saving policy to improve loading robustness:
- Exclude computed fields
- Exclude fields set to their default values
- Exclude fields with value None
- Use field aliases
- Recursively remove empty dictionaries and lists
- Ensure general.version is always present and correctly set
When loading older configuration files, computed fields are now stripped
before migration. This further improves backward compatibility and loading
robustness.
Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
Adapt uvicorn log level to allowed levels.
Ensure that EOSdash is started after EOS configuration is available.
Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
Adapters for Home Assistant and NodeRED integration are added.
Akkudoktor-EOS can now be run as Home Assistant add-on and standalone.
As Home Assistant add-on EOS uses ingress to fully integrate the EOSdash dashboard
in Home Assistant.
The fix includes several bug fixes that are not directly related to the adapter
implementation but are necessary to keep EOS running properly and to test and
document the changes.
* fix: development version scheme
The development versioning scheme is adaptet to fit to docker and
home assistant expectations. The new scheme is x.y.z and x.y.z.dev<hash>.
Hash is only digits as expected by home assistant. Development version
is appended by .dev as expected by docker.
* fix: use mean value in interval on resampling for array
When downsampling data use the mean value of all values within the new
sampling interval.
* fix: default battery ev soc and appliance wh
Make the genetic simulation return default values for the
battery SoC, electric vehicle SoC and appliance load if these
assets are not used.
* fix: import json string
Strip outer quotes from JSON strings on import to be compliant to json.loads()
expectation.
* fix: default interval definition for import data
Default interval must be defined in lowercase human definition to
be accepted by pendulum.
* fix: clearoutside schema change
* feat: add adapters for integrations
Adapters for Home Assistant and NodeRED integration are added.
Akkudoktor-EOS can now be run as Home Assistant add-on and standalone.
As Home Assistant add-on EOS uses ingress to fully integrate the EOSdash dashboard
in Home Assistant.
* feat: allow eos to be started with root permissions and drop priviledges
Home assistant starts all add-ons with root permissions. Eos now drops
root permissions if an applicable user is defined by paramter --run_as_user.
The docker image defines the user eos to be used.
* feat: make eos supervise and monitor EOSdash
Eos now not only starts EOSdash but also monitors EOSdash during runtime
and restarts EOSdash on fault. EOSdash logging is captured by EOS
and forwarded to the EOS log to provide better visibility.
* feat: add duration to string conversion
Make to_duration to also return the duration as string on request.
* chore: Use info logging to report missing optimization parameters
In parameter preparation for automatic optimization an error was logged for missing paramters.
Log is now down using the info level.
* chore: make EOSdash use the EOS data directory for file import/ export
EOSdash use the EOS data directory for file import/ export by default.
This allows to use the configuration import/ export function also
within docker images.
* chore: improve EOSdash config tab display
Improve display of JSON code and add more forms for config value update.
* chore: make docker image file system layout similar to home assistant
Only use /data directory for persistent data. This is handled as a
docker volume. The /data volume is mapped to ~/.local/share/net.akkudoktor.eos
if using docker compose.
* chore: add home assistant add-on development environment
Add VSCode devcontainer and task definition for home assistant add-on
development.
* chore: improve documentation
Improve documentation generation and add tests for documentation.
Extend sphinx by todo directive.
The configuration table is now split into several tables. The test
is adapted accordingly.
There is a new test that checks the docstrings to be compliant to the
RST format as used by sphinx to create the documentation. We can not
use Markdown in docstrings. The docstrings are adapted accordingly.
An additional test checks that the documentation can be build with sphinx.
This test takes very long is only enabled in full run (aka. ci) mode.
Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>