Repository navigation
feat(control): optional single-battery scope for manual hold #607
Copy link
Copy link
Closed
Labels
enhancementNew feature or requestNew feature or request
Description
Feature Description
Allow operators to pin a temporary battery setpoint to one specific battery driver, instead of always applying it to the whole site battery pool.
Default remains pool / aggregate control. Single-battery scope is an explicit opt-in at control time (UI + API).
Motivation
Community use case (Sourceful FTW Discord / #support):
- Multi-battery site
- One pack's internal cells are unbalanced
- Operator wants to charge only that pack toward ~100% during high PV so the BMS can rebalance
- Current
chargemode and/api/battery/manual_holdact on the aggregate pool, so all online batteries start charging
Today's workarounds (priority, temporary driver offline, vendor app) are clumsy for a common service/balancing task.
Proposed Solution
Extend manual hold with an optional driver scope:
API
POST /api/battery/manual_hold
{
"direction": "charge",
"power_w": 5000,
"hold_s": 900,
"driver": "battery_a"
}driveroptional; omit/empty = pool (current behavior)- GET returns the same
driverfield when scoped - Scoped semantics: target power on that battery only; other online batteries held at 0 W
- Existing SoC / per-driver caps / slew / fuse guard still apply
- Unknown driver → 400
- Expiry / DELETE clears hold and returns to selected site mode
UI
In <ftw-battery-control>:
- Scope: All batteries (default) | selected battery
- When opened from a battery card/planet, preselect that driver
- Active-hold banner shows scoped driver
Control loop
In ComputeDispatch manual-hold path:
- no driver → existing aggregate distribute
- with driver → scoped targets (hold power on that driver, 0 on others) then existing clamp/slew/fuse pipeline
Alternatives Considered
prioritymode — still site distribution, awkward for one-off balancing- Temporarily disable other drivers — drops telemetry, error-prone
- Vendor app full-charge — breaks FTW closed-loop
- Permanent per-battery modes — larger product surface than needed
Non-goals
- Permanent independent operating modes per battery
- Planner/MPC optimizing packs separately as first-class products
Scope / Effort Estimate
Medium — go/internal/control, go/internal/api battery manual hold, web/components/ftw-battery-control.js, unit tests.
Additional Context
- Site-EMS by design; multi-battery split is internal (
priority/weighted) - Manual hold already bypasses planner/idle short-circuits but keeps safety clamps — best extension point
- Discord: Fredrik approved capturing as a feature and starting a PR
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request
Activity
frahlg commentedon Jul 22, 2026
Control review after the battery-boost merge is complete.
The need in this issue remains, but it does not belong in the battery-boost lease contract. Battery boost grants one loadpoint short access to the home battery pool. This issue needs a short, in-memory service hold for one home battery. Both use the same Core safety path.
PR #608 now points at
a315acda3918b5b83f0b2ebfa4928d35490d1c23on currentmaster. The replacement binds a scoped hold to FTW's stable hardware ID, clears it on target or site safety failure, keeps restart fail-closed, and leaves every Core and driver limit in force. It does not change Lua drivers, driver-package data, or repository defaults.Local
make verify,npm test(67 passed), and the pre-pushmake verify-allpass. The PR stays draft until its field checklist passes. No merge has taken place.frahlg commentedon Jul 22, 2026
Update after
mastergained optimizer release work in #626: PR #608 has been rebased again without conflict. The new head is94802088a22fe28faa93ab645f42c841b472a1d6.make verifyand the pre-pushmake verify-allpass on that commit. The PR remains draft and has not been merged.