Skip to content

fix(control): reserve pending battery rises before releasing relief - #1816

Closed
segran2 wants to merge 2 commits into
srcfl:fix/fuse-one-functionfrom
segran2:fix/pending-battery-relief-1789
Closed

segran2 wants to merge 2 commits into
srcfl:fix/fuse-one-functionfrom
segran2:fix/pending-battery-relief-1789

Conversation

@segran2

@segran2 segran2 commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Ending battery discharge raises import just as adding charge does. The shared fuse allocator could spend phase room twice across pending rises, and could lose required relief when one of several batteries could not retain its allocated share. The mirrored export pass has the same allocation requirements when ending battery charge.

Stacked on #1789, targeting fix/fuse-one-function at c60da23. This is a bounded follow-up to that implementation, not adoption of #1763's different EV-reservation policy. Retarget after #1789 lands; do not merge independently into master.

Change

  • Include pendingW in capBatteryCharge's relief shortfall, as already done for positive charging-rise room.
  • Distribute retained relief over actually available supply: min(previously commanded relief that would end, current permitted relief). A blocked or floor-bounded battery no longer consumes a share another eligible battery can provide.
  • Retain only the required shortfall, up to available supply. When supply is insufficient, keep its permitted maximum without bypassing bounds or inventing new discharge/charge.
  • Import and export use the same helper with reversed signs. No Core fuse/load protection timing, driver commands, goals, settings or EV-under-delivery reservation policy changes.

Reproductions

Pending rise: 25 A three-phase site, 230 V, 1 A working margin; phases 22.3/12.3/12.3 A leave 1173 W room. A battery measures -2000 W, an unseen -1000 W command is pending, and the next target is 0. Before the original fix, 0 W is allowed (conditional 25.198551 A). Retaining -827 W limits the projected phase to 24 A. The export mirror retains +827 W.

Multiple batteries: at the same phase reading, A measures and was commanded -1000 W but is below its SoC floor; healthy B measures and was commanded -2000 W. Both targets are 0. Required retained relief is 3000−1173 = 1827 W. On prior head c2246d1, proportional allocation assigned 609 W to A and 1218 W to B, then discarded A's unavailable share. B=-1218 W projects 24.882609 A. The new head gives A=0, B=-1827 W: conditional 24 A. Export with a charge-blocked battery is covered by the same tests.

These are conditional balanced-response calculations assuming unchanged other loads and response before the next correction, not measured overcurrent or evidence of fuse operation. Infeasible bounds cannot guarantee the working limit.

Validation — head 1d13585

  • Full make verify passed: Go suites, script checks, native worker checks, vet and build.
  • Full control suite passed, including existing golden/scenario tests. No golden updates or new failure exemptions.
  • Full go test -race ./internal/control ./internal/telemetry ./internal/loadpoint -count=1 passed.
  • 34 new leaf regression cases pass. The exact final tests fail in 30 cases on prior head c2246d1.
  • Cases cover blocked and partially bounded supply, insufficient total relief, no prior supply, pending rises exceeding supply, both battery orders, allocation/manual/idle paths, import and mirrored export. Complete-dispatch fixtures disable the separate slew limiter only to isolate fuse admission; no real settings changed.
  • The original pending-rise regressions remain green.
  • All 31 identical-input comparison decisions used against fix(control): reserve EV demand until offered power is delivered #1763/fix(control): fuse protection as one function #1789 pass with the fixed helper, plus the independent minimal helper reproduction. The EV-under-delivery policy difference remains: the original comparison's 280.4 W versus 6000 W battery targets are intentional branch policy, not changed here.
  • Telemetry-read ratchet and diff whitespace checks pass. No new telemetry reads.
  • Docker-context and live Avahi checks skipped because Docker was unavailable.
  • No final-head full GitHub CI acceptance is claimed on this feature-branch target.

Acceptance and history

The 25 October comparison of #1763 7361f9d, #1789 c60da23 and previous #1816 c2246d1 exposed the redistribution failure above at allocation, idle and manual layers; a pure helper test confirmed it without telemetry adapters. This follow-up addresses that finding, while retaining #1816's earlier pending-rise correction.

Review of this follow-up, #1789/current-master integration, the separate EV-reservation policy decision and affected-hardware acceptance remain outstanding. GitHub's existing ready-for-review flag was left unchanged. No branch was merged, no channel/release published and no running household FTW, driver, history or settings modified.

@segran2
segran2 marked this pull request as ready for review October 24, 2026 22:22
Signed-off-by: Segran <goran@andersson-stehag.se>
frahlg added a commit that referenced this pull request Oct 28, 2026
…1918)

* test(control): port #1816's battery relief reproductions to master

Two reproductions from #1816, adapted to master's
capBatteryCharge and clampEVBatteryHeadroom:

- Pending rise: 25 A site, 1 A margin, phases 22.3/12.3/12.3 A. The
  battery measures -2000 W and our newer -1000 W order may not show yet.
  Ending the relief must keep -827 W so L1 lands on 24 A, not 25.2 A.
- Shared relief: two batteries end -1000 W and -2000 W of relief. When
  the first cannot keep its share (SoC floor or a 300 W bound), the
  second keeps the missing 1827 W instead of the old 1218 W.

Master's keepEndingDischarge (#1847) passes both. Dropping it, ignoring
pending rises, or sharing before bounds makes them fail. Import only:
master leaves the export direction to the fuse pipeline.

Co-authored-by: segran2 <268038031+segran2@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(control): say which relief gaps master leaves open

The header said master leaves the export case to the fuse pipeline.
Nothing on master holds it. Name both no-car gaps instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: segran2 <268038031+segran2@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@frahlg frahlg closed this in #1918 Oct 28, 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.

1 participant