-
-
Notifications
You must be signed in to change notification settings - Fork 6
candidate generation
This document explains how candidate plans are generated, how assumptions drive the candidate set, and the mathematical models behind each strategy.
- Why multiple candidates?
- Candidate list
- Assumptions behind each candidate
- MILP global optimisation
- Hysteresis
Battery scheduling is a sequential decision problem under uncertainty (prices, PV, and load are forecasts, not certainties). A single heuristic strategy may miss the global optimum under certain market conditions. By evaluating multiple independent strategies and picking the cheapest valid one, the planner:
- Captures more of the available arbitrage value
- Degrades gracefully when forecasts are wrong
- Provides explainable alternative plans for debugging
The generator (planner/candidate_generator.py) operates in MILP-only mode.
The MILP finds the globally optimal solution; heuristic candidates are disabled
because the MILP consistently dominates them. Only diagnostic baselines remain
alongside the MILP:
| # | Name | Strategy |
|---|---|---|
| 1 | no_action |
Battery completely idle — no forced charge or discharge |
| 2 | passive |
Solar charging only where PV surplus exists; no grid charge or forced discharge |
| 3 | milp |
Globally-optimal LP solution (when scipy is available) |
The following candidates were previously generated but are now commented out in MILP-only mode. They remain documented for reference and may be re-enabled as diagnostic tools:
| Name | Strategy |
|---|---|
baseline |
Current HSEM scheduling output (discharge → charge → excess export → optimisation) |
grid_charge |
Grid-charge slots kept; solar charging removed |
solar_only |
Only solar-charge slots kept; grid charging cleared |
discharge_only |
Discharge slots kept; all charge slots cleared |
aggressive |
Cheapest N slots forced to grid-charge; most expensive M slots forced to discharge |
soc_plan_25/50/75/100/125/full |
Partial-SoC candidates charging different fractions of discharge-window need |
Assumption: The inverter can be left in its default self-consumption mode (no external scheduling). PV surplus is exported; battery only moves according to its native operating logic.
Purpose: Provides a baseline cost that all other candidates must beat.
If no candidate beats no_action, the planner falls back to doing nothing.
Mathematical model:
- All recommendations cleared to
None - No grid charge, no forced discharge, no force export
- SoC simulation still runs: PV charges battery if native logic would do so
- Terminal SoC is still accounted for
Assumption: The inverter's default behaviour is solar-following — it charges from PV surplus when available and stays idle otherwise. No grid price arbitrage.
Purpose: Models what happens if HSEM only sets PV-charge recommendations without any grid-based scheduling.
Mathematical model:
- Solar surplus slots (where
estimated_net_consumption < 0) getbatteries_charge_solar - All other charge/discharge/export recommendations cleared
- Battery fills from PV, never from grid
- Battery never discharges unless native inverter logic does so
The MILP solver (planner/milp_optimizer.py) uses scipy's HiGHS to find the
globally optimal charge/discharge schedule. This is the primary planner —
the MILP solution is preferred over all heuristic candidates.
See MILP Optimization for the full LP formulation, variable layout, constraints, solver pipeline, and post-processing flow.
When one or more active EVs are provided, the MILP co-optimises EV charging alongside the battery schedule. EV charging variables are added to the LP variable vector and the energy balance equation includes EV charger load.
If scipy is unavailable or the solver fails (infeasible / numerical issue),
the MILP candidate is silently dropped and the remaining candidates
(no_action, passive) compete as normal.
Prevents the planner from switching strategies for tiny cost improvements. When active:
- The previously active plan is re-evaluated with current data
- If its score improvement over the best new candidate is below both thresholds, the previous plan is kept
| Threshold | Default | Behaviour |
|---|---|---|
| Absolute | 0.0 currency | New plan must be cheaper by at least this amount |
| Percentage | 5.0 % | New plan must be cheaper by at least this % of previous score |
Prevents rapid charge↔discharge toggles near schedule-window boundaries.
-
Charge-type:
batteries_charge_grid,batteries_charge_solar,ev_smart_charging -
Discharge-type:
batteries_discharge_mode,force_batteries_discharge,force_export -
Neutral:
batteries_wait_mode,time_passed,missing_input_entities,None
Only cross-category transitions are held. The hold time is configured by
planner_window_hysteresis_minutes (default: 0, disabled).
- Home — User-facing overview: features, FAQ, working modes, battery schedules, excess export, consumption sensors
- Battery Charging Economics — How to calculate the minimum charging price for a battery schedule
- Architecture Overview — System context, layered architecture, module map, planning pipeline
- Planner Specification — Normative — all planner invariants, rules, and constraints
- Planner Technical Guide — How the planner works with worked examples
- Cost Function Math — Complete mathematical formulation of the 8-term cost function
- Energy Accounting — Physical energy flow model, SoC simulation, efficiency math
- Candidate Generation — How candidates are generated, assumptions, partial-SoC
- MILP Optimization — Full LP formulation, variable layout, constraints, and solver pipeline
- Consumption Prediction — Weighted-average model, IQR outlier detection, spike suppression
- Safety Modes — Degraded mode, read-only gate, write-verify applier, runtime resolver
- Price Scaling — EDS price scaling, eds_share conversion factor
- Services Reference — All 4 HSEM services with examples
- Sensors Reference — Complete entity reference: all sensor, select, switch, number, and time entities
- Dashboard Setup — Step-by-step ApexCharts dashboard with full YAML, layout reference, and troubleshooting
- Config Flow Reference — Every config/options flow step and field
- EV Charge Plan Setup — EV planned load configuration guide
- EV Surplus Charging Automation — Wire your physical EV charger (go-e, Easee, Zaptec) to follow HSEM surplus recommendations
- EV Optimal Charging Template — Legacy Home Assistant template sensor for cost-optimal EV charging
- Forecast Accuracy Tracking — Forecast vs actual tracking system
- Huawei Entities — Canonical HA entity ID reference
- Troubleshooting Guide — Diagnose and fix common problems: missing data, wrong prices, write failures, battery behaviour
- Quality Checks — Static quality tools and CI configuration