Model curtailment on a negative export price (#3986)#4023
Conversation
Predbat modelled export using a static export_limit regardless of the slot export price, so negative-price slots that are curtailed in reality were still booked as exported (a phantom export cost) and the projected economics did not match reality. Add an optional, off-by-default control that models this curtailment without driving it - the actual curtailment stays with the user's inverter or automation: - curtail_on_negative_export_price (select): "off" (default) models no curtailment; "curtail_excess" models grid export as blocked whenever the export price is negative, while PV still charges the battery and supplies the house; "solar_production_off" models the PV as fully off, for inverters that can only disable generation rather than limit export. run_prediction caps the effective export limit to zero for negative-price slots when enabled, and zeroes PV generation in the solar_production_off mode. Add model test scenarios for both modes at a negative price, and a guard that curtailment does not trigger when the export price is positive. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pv_calibration compares ~7 days of measured pv_today against the historical forecast and scales the forecast by actual/forecast. It cannot tell panel underperformance apart from deliberate curtailment, so when generation is curtailed during negative-price slots the measured generation drops and calibration reads it as underperformance, dragging the forecast down (clamped as low as 20%). This hits Forecast.Solar users hardest, as they have no auto-dampening. Add slot_export_curtailed(rate), and reconstruct the historical export rate per slot from the recorded history of the predbat.rates_export entity (whose state is the export rate at each point in time), the same way the forecast history is fetched. Use it to skip negative-price curtailed slots when building both the actual and forecast calibration aggregates, keeping the per-slot and per-day scaling factors consistent. Slots with no known historical rate are kept (conservative), and with the feature off nothing is excluded, so calibration is unchanged for existing users. Add a unit test for slot_export_curtailed covering both modes, the off state, the strict negative comparison, and unknown rates, plus a guard that pv_calibration queries the predbat.rates_export entity. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…#3986) In the HTML plan, mark PV modelled as curtailed on a negative export price with a distinct colour, so curtailed solar is visually separated from solar that is normally exported. No new columns or fields are added, keeping the Predbat table card intact. With the feature off this never triggers, so the plan is unchanged for existing users. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…#3986) Document the new curtail_on_negative_export_price control under Solar PV adjustment options in customisation.md (next to the PV calibration setting it relates to), add a conceptual explanation to energy-rates.md, and cross-reference it from the export_limit entry in apps-yaml.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Looks good, but the use of 'off' is incorrect it should be False/True for apps.yaml settings. Let me know if you are okay to update? |
|
Cross-referencing #4036 (Native Solar Clipping Buffer) for coordination — the two are complementary, but they touch overlapping files, so whichever merges second will need a rebase. Both deal with PV that can''t be exported, but via a different trigger and mechanism:
The original request in #3986 noted that the static export/DNO-limit cases would need a deeper change that actively lowers SoC ahead of high-generation days — which is exactly what #4036 tackles. So they complement rather than duplicate each other. Overlap heads-up: both touch |


What this does
Implements the request in #3986: lets Predbat model the curtailment of export that many of us apply when the export price goes negative (e.g. an automation that sets the inverter''s export limit to zero while
export_price < 0). Predbat does not drive the curtailment — it only models it, so the feature is inverter-agnostic and adds no new control failure modes.Why
With a static
export_limit, Predbat models export as proceeding normally during negative-price slots, causing two problems:pv_calibrationreads it as panel underperformance, dragging the forecast down (clamped as low as 20%). This hits Forecast.Solar users hardest, as they have no auto-dampening.What''s included
select.predbat_curtail_on_negative_export_price(expert mode, defaultoff):off— no curtailment modelled (existing behaviour, unchanged).curtail_excess— grid export modelled as blocked whenever the export rate is negative, while PV still charges the battery and supplies the house.solar_production_off— PV modelled as fully off during negative-price slots, for inverters that can only disable generation rather than limit export.prediction.py) — per slot, when enabled andexport_rate < 0, the effective export limit is set to zero (and PV to zero insolar_production_off).solcast.py) — negative-price slots are excluded from the calibration input (both the actual and forecast aggregates), using the recorded history of thepredbat.rates_exportentity, so calibration can stay enabled without curtailment being mistaken for underperformance.output.py) — curtailed PV is shown in a distinct colour; no new columns/fields, so the Predbat table card is unaffected.customisation.md,energy-rates.md,apps-yaml.md.Design note
The original issue proposed a configurable price threshold. In testing, the only sensible threshold turned out to be 0 (curtail when the price is negative); a configurable value mainly added confusion, and export fees can be folded into the rate sensor instead. So the trigger is fixed at
< 0, and the control is a singleselectthat also captures the two real curtailment behaviours (export-only vs full PV-off).Off by default
With the default
off, nothing changes for existing users. The feature is modelling-only; the actual curtailment stays with the user''s inverter or automation.Testing
Closes #3986.