v7.10.0: Solar clipping awareness for DC-coupled hybrid inverters#58
v7.10.0: Solar clipping awareness for DC-coupled hybrid inverters#58pookey wants to merge 4 commits intojohanzander:mainfrom
Conversation
The optimizer previously had no awareness of inverter AC output limits, so it would grid-charge or solar-store the battery before peak solar hours, wasting free DC-excess energy that the inverter could not convert to AC. When `battery.inverter_ac_capacity_kw` is configured, the Solcast forecast is split into AC solar (≤ inverter limit) and DC-excess solar (the portion that flows directly to the battery on the DC bus). The DP algorithm receives both and automatically absorbs DC excess before evaluating AC-side charge/discharge decisions. Because DC-excess energy carries zero grid cost (only cycle cost), backward induction naturally reserves battery headroom for clipping hours over grid charging — no special heuristics needed. New EnergyData fields `dc_excess_to_battery` and `solar_clipped` expose captured vs lost DC excess per period for dashboard visibility. When `inverter_ac_capacity_kw = 0` (default), behaviour is unchanged.
|
This is still in testing - I'll not be able to verify it's effectiveness until there's another funny day in the UK, so might be a few years ;) |
Code reviewFound 4 issues:
Lines 135 to 138 in b09a8f2
bess-manager/core/bess/dp_battery_algorithm.py Lines 134 to 144 in b09a8f2
bess-manager/core/bess/models.py Lines 153 to 170 in b09a8f2
bess-manager/core/bess/dp_battery_algorithm.py Lines 222 to 225 in b09a8f2 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
1. Schema fields: inverter_ac_capacity_kw and solar_panel_dc_capacity_kw changed from `float` to `float?` so existing users can upgrade without HA rejecting their config before Python runs. 2. split_solar_forecast docstring: removed misleading "0 = no limit" since passing 0 would cap AC to zero. Clarified that the caller must guard with `if inverter_ac_capacity_kw > 0`. Replaced the zero-limit test with a total-preservation test. 3. validate_energy_balance: documented that DC excess bypasses the AC bus and is balanced by definition (dc_excess_to_battery + solar_clipped = total DC excess). The AC-side balance holds by construction since grid flows are derived from the balance equation. 4. Cycle cost policy docstring: updated to reflect that DC wear cost is applied regardless of AC action (not only during charging).
Add dcExcessToBattery and solarClipped FormattedValue fields to /api/dashboard per-period response. Add inverterAcCapacityKw and solarPanelDcCapacityKw to /api/settings/battery response. Update bess-analyst agent with API visibility and debugging steps. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The DP was treating IDLE (power=0) as a flat hold, but on the Growatt inverter IDLE maps to load_first mode where excess solar automatically charges the battery before exporting. This caused the optimizer to underestimate morning SOE buildup, leaving insufficient headroom for afternoon DC excess absorption. Changes: - _state_transition: when power=0, excess solar auto-charges battery up to max_charge_power_kw and available capacity (load_first behavior) - _calculate_reward: detects IDLE auto-charging from SOE delta, models reduced grid export and applies cycle wear cost on auto-charged energy; blends auto-charged solar into cost basis at cycle-cost-only rate - _run_dynamic_programming: computes solar_excess_ac_kw per period (capped at temperature-derated limit), passes to _state_transition; updates fallback IDLE block and cost basis propagation accordingly - _create_idle_schedule: added dt parameter, now models solar auto-charging in fallback schedule for accurate idle cost accounting The DP's backward induction now sees that IDLE during morning solar fills the battery, reducing headroom for free DC excess. When keeping headroom is more valuable, it chooses discharge/EXPORT_ARBITRAGE (grid_first) which prevents solar auto-charging on the real inverter — no new intent types needed. Backward compatible: no solar or nighttime periods are unchanged.
|
Updated this branch with an additional fix discovered after deploying the clipping feature. Bug: The DP was modelling Evidence (2026-03-18): Periods 30–39 were planned as IDLE, but battery charged from 1.4 → 7.2 kWh (5.8 kWh gain). By period 40 (10:00) battery was at 76% with only 2.1 kWh headroom despite >5 kW solar forecast all afternoon. Fix: Model IDLE auto-charging in Backward compatible: no solar / nighttime periods are unchanged. |
|
Hi @pookey , sorry for not merging this one sooner, and now I have refactored the algorithm (or fixed some issues), so I cannot safely merge the changes. Could you rebase and verify your fix and I will merge it? |
Summary
battery.inverter_ac_capacity_kwis configured, the Solcast forecast is split into AC solar (≤ inverter limit) and DC-excess solar. The DP algorithm absorbs DC excess before its AC-side charge/discharge decision. Because DC-excess energy has zero grid cost (only cycle cost), backward induction naturally keeps battery headroom open during clipping hours — no heuristics needed.inverter_ac_capacity_kw = 0(default) gives identical behaviour to v7.9.5.Changes
config.yaml: newbattery.inverter_ac_capacity_kwandbattery.solar_panel_dc_capacity_kwoptionssettings.py: newBatterySettingsfields loaded from configmodels.py:EnergyDatagainsdc_excess_to_batteryandsolar_clippedfieldsdp_battery_algorithm.py:split_solar_forecast(), DC-aware_calculate_reward,_run_dynamic_programming,optimize_battery_schedule, and_create_idle_schedulebattery_system_manager.py: wires upsplit_solar_forecastin_run_optimizationapi_dataclasses.py:dcExcessToBatteryandsolarClippedexposed in/api/dashboardper-period response;inverterAcCapacityKwandsolarPanelDcCapacityKwexposed in/api/settings/batteryapi.py: quarterly-to-hourly aggregation sums the new clipping fieldsDemonstration:
We can see headroom being left in the. battery during the peak.
Test plan
blackandruffcleaninverter_ac_capacity_kw: 5.0andsolar_panel_dc_capacity_kw: 6.7in config, run optimization, verify schedule defers grid charging to after peak clipping hoursdcExcessToBatteryandsolarClippedappear in/api/dashboardperiod datainverterAcCapacityKwandsolarPanelDcCapacityKwappear in/api/settings/battery🤖 Generated with Claude Code