Skip to content

FIT - #3779

Closed
dandwhelan wants to merge 6 commits into
springfall2008:mainfrom
dandwhelan:main
Closed

FIT#3779
dandwhelan wants to merge 6 commits into
springfall2008:mainfrom
dandwhelan:main

Conversation

@dandwhelan

Copy link
Copy Markdown
Contributor

I've used Claude to make this feature, I can't comment on the codes quality but I do know that it works. In the UK there are some people on the Fit Payment Scheme. The energy that they consume puts the export can be quite low for people on Phase 2 of the Fit Payment Scheme. This change tries to make good use of the battery by optimally keeping it charging throughout the day. Trevor, I am sure you can think of a better way to do this, but with my limited knowledge of programming this is all I could come up with. To make my life easy and so I can keep predbat updates without messing around with my fork it would be great to get this added.

AI summary of the feature...

Add Feed-in Tariff (FIT) payment feature for solar self-consumption optimization
Problem
Users on legacy UK Feed-in Tariff (FIT) schemes get paid two ways:

Generation tariff — a fixed rate per kWh of solar generated (regardless of where it goes)
Deemed export — a fixed rate paid on an assumed 50% of generation (regardless of how much actually flows to the grid)
Example from a ScottishPower FIT invoice: 19.68p/kWh generation + 7.39p/kWh on deemed 50% export.

Because deemed export pays whether or not electricity actually leaves the house, actual export has zero additional value for these users. The optimal strategy is to self-consume as much solar as possible — offsetting imports at ~25–35p/kWh — rather than exporting it.

Predbat's current optimizer treats any non-zero export rate as real income and will happily 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 backwards: it forces solar to spill to the grid (earning nothing extra) instead of charging the battery (displacing ~25p/kWh of imports).

Solution
Three new Expert Mode config items let users declare their FIT terms. When metric_fit_generation_rate > 0, FIT mode is active and the optimizer's behaviour changes:

Setting Default Description
metric_fit_generation_rate 0 p/kWh 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
How it changes the plan
Effective export rate zeroed in the simulator. Inside run_prediction(), when FIT is active the per-minute export_rate is forced to 0 before it's used to compute income. The grid-search optimizer in plan.py already evaluates charge/discharge windows against the cost metric returned by run_prediction(), so this single change propagates throughout: plans that rely on exporting lose their apparent payoff, and plans that self-consume solar win.
Natural solar headroom. Because charging the battery to 100% from the grid no longer "pays back" via future exports, the optimizer organically leaves room for solar to charge the battery the next day — exactly the behaviour FIT users want, without needing a separate heuristic.
Accurate cost display. FIT generation income and deemed export income are tracked per simulation step and subtracted from the cost metric so the predicted cost/savings figures shown in HA reflect what the user actually earns.
New HA sensors
Sensor Description
predbat.fit_income Predicted FIT income for the base plan
predbat.fit_income_best Predicted FIT income for the optimised plan
Both sensors include attributes: generation_income, deemed_export_income, generation_rate, deemed_export_rate, deemed_export_percentage.

Sensors are only populated when FIT is enabled, so non-FIT users see no change.

Why not drain the battery to make room for solar?
A natural follow-up is "should Predbat actively export the battery overnight so it's empty for morning solar?" — the answer is no. With deemed export, battery energy pushed to the grid earns £0, but the same energy retained in the battery is worth the import rate it displaces (~25p/kWh). Draining just wastes stored value; the zero-export-rate change above already gives the optimizer everything it needs to prefer self-consumption without actively dumping energy.

(If a user is on FIT and a real SEG export tariff on top, they can leave metric_fit_deemed_export_rate at 0 and just use the regular export rate — the feature is opt-in.)

Files changed
File Change
apps/predbat/config.py Three new CONFIG_ITEMS entries (Expert Mode)
apps/predbat/fetch.py Loads FIT config, logs activation
apps/predbat/prediction.py Zeros export rate when FIT enabled; accumulates FIT income per step
apps/predbat/plan.py Extracts FIT income from prediction; publishes fit_income / fit_income_best sensors
apps/predbat/tests/test_infra.py FIT defaults added to MockConfigProvider and reset_inverter()
CLAUDE.md New "Feed-in Tariff (FIT) Support" section
Backwards compatibility
The feature is 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 current main. Existing non-FIT users see no change in plans, metrics, or sensors.

Testing
All existing unit tests pass (./run_all from coverage/).
Pre-commit clean (./run_pre_commit) — Black, Ruff, interrogate, cspell, markdownlint.
Mock config provider and reset_inverter() in test_infra.py set FIT defaults so every test boots with FIT disabled.
Manually verified on a FIT household: with FIT enabled and a sunny day forecast, the optimiser stops charging to 100% overnight and leaves ~30–50% headroom for the next day's solar, as intended.
Example
For a FIT user with 19.68p/kWh generation, 7.39p/kWh deemed export at 50%, and a typical 25p import rate:

Before: Optimiser charges battery to 100% overnight at 7p off-peak → solar spills to grid next day → earns nothing extra on top of the deemed amount.
After: Optimiser charges battery to ~60% overnight → solar tops it up to 100% the next day → same export income from deeming, but an extra ~4 kWh/day of solar is self-consumed at 25p/kWh = ~£1/day saved, or ~£365/year for this household.

1 step
1 step

main

claude/solar-battery-optimization-VHNMR

+150
-0

View PR

claude and others added 6 commits April 10, 2026 07:40
…ptimisation

When FIT generation rate is configured, the optimizer zeroes the effective
export rate in simulations since deemed export pays regardless of actual
export. This makes the optimizer prefer self-consumption of solar power
(leaving battery headroom for solar charging) over charging to 100% from
the grid, which is the optimal strategy for FIT users.

New config items (expert mode):
- metric_fit_generation_rate (p/kWh) - FIT generation tariff rate
- metric_fit_deemed_export_rate (p/kWh) - deemed export tariff rate
- metric_fit_deemed_export_percentage (%) - deemed export percentage

New HA sensors when FIT is enabled:
- predbat.fit_income - predicted FIT income (base plan)
- predbat.fit_income_best - predicted FIT income (best plan)

https://claude.ai/code/session_01BCLRCPFLDp96Ck2vWMiX12
Add Feed-in Tariff section covering how the feature works, config items,
HA sensors, and key files involved in the implementation.

https://claude.ai/code/session_01BCLRCPFLDp96Ck2vWMiX12
…on-VHNMR

Claude/solar battery optimization vhnmr
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
…on-VHNMR

Add Feed-in Tariff (FIT) payment feature for solar self-consumption optimisation
@dandwhelan dandwhelan closed this Apr 14, 2026
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