Skip to content

Add Feed-in Tariff (FIT) payment feature for solar self-consumption optimisation#2

Merged
dandwhelan merged 1 commit into
mainfrom
claude/solar-battery-optimization-VHNMR
Apr 12, 2026
Merged

Add Feed-in Tariff (FIT) payment feature for solar self-consumption optimisation#2
dandwhelan merged 1 commit into
mainfrom
claude/solar-battery-optimization-VHNMR

Conversation

@dandwhelan

Copy link
Copy Markdown
Owner

Summary

Users on legacy UK Feed-in Tariff (FIT) schemes receive a generation tariff on all solar produced and a deemed export payment on a fixed percentage (typically 50%) of generation — regardless of how much electricity actually flows to the grid. This means actual export has zero additional value for these users. The optimal strategy is self-consumption: using solar to charge the battery and offset imports (~25–35p/kWh) rather than spilling it to the grid.

Predbat's optimizer previously treated any non-zero export rate as real income and would charge the battery to 100% from cheap overnight grid slots, leaving no headroom for the next day's solar. For a FIT user this is counterproductive — it forces solar to spill to the grid (earning nothing extra) instead of charging the battery.

Changes

Three new Expert Mode config items (config.py)

Setting Default Description
metric_fit_generation_rate 0 p/kWh FIT generation tariff rate
metric_fit_deemed_export_rate 0 p/kWh Deemed export tariff rate
metric_fit_deemed_export_percentage 50 % Deemed export assumed percentage

When metric_fit_generation_rate > 0, FIT mode is active.

How the optimiser changes (prediction.py)

The per-minute export_rate is zeroed inside run_prediction() when FIT is active. The grid-search optimiser in plan.py evaluates charge/discharge windows against the cost metric returned by run_prediction(), so this single change propagates everywhere: plans that rely on exporting lose their apparent payoff, and plans that self-consume solar win naturally — leaving battery headroom for the next day's solar without any separate heuristic.

FIT generation income and deemed export income are tracked per simulation step and subtracted from the cost metric so predicted cost/savings figures reflect actual FIT earnings.

New HA sensors

Sensor Description
predbat.fit_income Predicted FIT income (base plan)
predbat.fit_income_best Predicted FIT income (best/optimised plan)
predbat.fit_income_yesterday FIT income for yesterday's baseline prediction

All sensors include attributes: generation_income, deemed_export_income, generation_rate, deemed_export_rate, deemed_export_percentage. Sensors are only published when FIT is enabled — non-FIT users see no change.

Yesterday savings calculations (output.py)

The FIT export zeroing already applied correctly to both yesterday simulations (the Prediction object inherits FIT config from the PredBat instance). Added extraction of FIT income from those simulations and publication of the fit_income_yesterday sensor so users can see yesterday's FIT income breakdown.

Backwards compatibility

Fully opt-in and defaults off. With metric_fit_generation_rate = 0 (the default), every code path is a no-op and behaviour is identical to the current main. Existing non-FIT users see no change in plans, metrics, or sensors.

Files changed

File Change
config.py Three new CONFIG_ITEMS entries (Expert Mode)
fetch.py Loads FIT config, logs activation
prediction.py Zeros export rate when FIT enabled; accumulates FIT income per step
plan.py Extracts FIT income from prediction; publishes fit_income / fit_income_best
output.py Extracts FIT income from yesterday predictions; publishes fit_income_yesterday
tests/test_infra.py FIT defaults added to MockConfigProvider and reset_inverter()
CLAUDE.md New "Feed-in Tariff (FIT) Support" section

Test plan

  • All unit tests pass (./run_all from coverage/)
  • Pre-commit clean — Black, Ruff, interrogate, cspell, markdownlint all pass
  • Mock config provider and reset_inverter() set FIT defaults to off so every existing test boots with FIT disabled
  • Verify on a FIT household: with FIT enabled and a sunny day forecast, the optimiser stops charging to 100% overnight and leaves headroom for solar

https://claude.ai/code/session_01BCLRCPFLDp96Ck2vWMiX12

Extract FIT generation and deemed export income from the yesterday
prediction simulations in calculate_yesterday() and publish a new
predbat.fit_income_yesterday sensor so users can see yesterday's
FIT income breakdown alongside the existing savings sensors.

https://claude.ai/code/session_01BCLRCPFLDp96Ck2vWMiX12
@dandwhelan dandwhelan merged commit c66c0ef into main Apr 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants