Files
goodwe-addon/goodwe_controller/DECISIONS/TARIFF-24-modes-need-the-tariff-task.md
T
glenn schrooyenandClaude 382b0ea411 TARIFF-24 round 2: a usable solar forecast replaces the "no weather" x1.5 (AUDIT-02 F1)
With battery modes on, the price gap a mode needs was always widened x1.5 by
Uncertainty.NO_WEATHER, even with a solar forecast read, so a 0.08 day/night
gap never traded at the shipped cycle cost. The doubt is now added only when
no usable forecast is read (solar_fc is None, the day plan's own test), in the
run plan (_price_runs), the charge gate (_mode_roles) and Home's mirror
(homeview.trade_verdict). The rule is one helper, arbitrage.weather_uncertainty();
the modes-off trade path (main.py cycle) keeps its literal NO_WEATHER.

DOCS "Battery modes" sentence, CHANGELOG 0.19.1 line and the DECISIONS note
follow. Tests: test_tariff24_weather.py.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-28 15:08:21 +01:00

3.6 KiB

TARIFF-24 - battery modes need the tariff task

Status: FIXED in 0.19.1 (hotfix from 0.19.0, owner go 2026-10-28). Follows TARIFF-10 (fetching is not trading). Tests: test_tariff24.py.

The defect. The control cycle gets prices only from Controller.tariff_plan, which only run_tariff_refresh() stores. amain() starts that task when tariff_refresh_wanted(opts), which was provider_configured(opts) or arbitrage.enabled(opts). Battery modes read the plan but were not a term. With battery modes on, a day/night or fixed static_profile, price_provider: off and arbitrage_enabled: false (the site trade switch is not read with modes on) no task ran. Then fresh_tariff_plan() was None, _price_runs() was None and mode_runs was None, so Leftover solar and Cheap hours never charged from the grid. The Batteries screen said "No prices, so it follows the house" while Home priced the day from static_plan() itself (homeview.build_plan()).

The fix (main.py, tariff_refresh_wanted()). packmode.enabled(opts) is a third term. The gate stays a widening: nothing that started the task before stops. No HTTPS call is added: with price_provider: off, resolve_tariff() is the pure static_plan().

Not changed. Modes off, arbitrage off, no feed still starts no task. The control law, the price runs and every message are untouched.

One rule, not two. Gating on "modes on and a static profile" was considered. It saves one arithmetic pass every 30 min on a site with modes on and no prices at all, and it adds a second condition that has to track what resolve_tariff() accepts. With no profile and no feed the plan is no_data, exactly what the cycle sees without the task.

UX-55. Home said "no prices have arrived" (mode_runs None) with every battery on Solar first. The same cause, and this fix clears it for a site with a static profile (test_tariff24.py part 5). A site with no profile and no feed still has no prices, and Home still says so.

Round 2 (AUDIT-02 F1): the forecast replaces the "no weather" doubt

Decided 2026-10-28 (owner), in the same hotfix. The price gap a mode needs was cycle_cost_threshold_eur x 1.5 (Uncertainty.NO_WEATHER) whether or not a solar forecast was read. At the shipped cost 0.10 that is 0.15, so a day/night gap (0.08) and many dynamic days never traded, and the screens said only "Prices differ too little".

Why the doubt goes with a forecast. The widening stands in for not knowing the weather. The forecast is that knowledge, and the day plan already trusts it for how much to charge. Trusting it for the plan but doubting it for the gap was one input judged twice.

The rule (arbitrage.weather_uncertainty()). With battery modes on and a usable forecast (solar_fc not None, the day plan's own test) the doubt is not added: the gap needed is the cycle cost, widened by the price product only. No forecast, or a stale or unusable one: 1.5 x, as before. It is read in three places that must agree: the run plan (_price_runs()), the charge gate (_mode_roles()) and Home's mirror (homeview.trade_verdict()). The forecast is read at most every 60 s and the plan key already holds "forecast or not", so the gap follows in the cycle the read changes, both ways. A run already under way is kept to its end (priceruns.keep_started()), as for any change.

Not changed. Modes off (the site trade) keeps the doubt always. The shipped cost 0.10 still needs a gap of 0.10 even with a forecast: a 0.08 day/night site must set Battery cycle cost to 0.08 or less. Showing the two numbers on the screens (AUDIT-02 F1 option b) is a separate card.