foxess_h3_smart 0.9.5: pending charge goes universal — the BMS limit follows activity, not capability - #98
Conversation
…lows activity, not capability (0.9.5) 0.9.4 fixed the night refusal loop but kept the instant refusal in daylight, and the same loop promptly reappeared with the sun up: a battery idle at the SoC floor under weak PV dozes off and reports no charge headroom even in daylight (two incidents on the discovering 1K5, 2026-08-19/20: SoC 11-14%, battery 0 W, limit below the floor; the host re-commanded every 5 minutes and the fault flapped indefinitely, paging the operator). A floor-level limit now always accepts the charge as pending: hold the battery at zero (night: AC = 0; daylight: AC = pv so PV passes to house and grid), keep the session alive, re-read the limit every poll, apply the true setpoint the moment it rises, give up after the 3 min patience window. A genuinely full or cold pack costs at most 3 minutes of held-zero before native self-use resumes. Also corrects the incident dates the 0.9.4 notes carried (August, not September; author error). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Leitet <johan@sourceful-labs.com>
Live metric data (2026-08-20 morning, the discovering 1K5): the BMS limit register stayed exactly 0 for 12+ minutes across held-at-zero pending sessions at the SoC floor -- Pwr_limit_Bat_up follows power FLOW, not capability, and a session that asks for nothing never wakes the pack. The unguarded v0.2.0 charged 4.5 kW from this exact idle state just by asking: asking is the wake-up call. The pending state now commands a 200 W probe charge (night: AC = -200; daylight: AC = pv - 200) -- below the refusal floor, harmless to a genuinely full pack, bounded by the 3 min patience window. The full setpoint still waits for the register to actually rise; the BMS-ceiling invariant is untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Leitet <johan@sourceful-labs.com>
… is dead Live metric data went one step further than the probe design assumed: Pwr_limit_Bat_up stayed flat 0 even while the pack demonstrably charged at the probe level. In the idle-at-floor state the register is not slow -- it is dead, and register-gated escalation can never fire. Capability is now read from measured uptake when the register sleeps: the request ramps 500 W per poll while the battery follows (half the current request as the follow threshold), decays one step on stalls rather than resetting (the inverter can lag a poll behind), never exceeds the commanded target, and hands over to the register path the moment the register actually rises. The patience window only counts time without uptake -- a charging pack is success in progress, not a refusal to time out. This is the uptake-feedback loop the header's charge section always named as the next step, arrived at with the hardware evidence it asked for. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Leitet <johan@sourceful-labs.com>
|
Live validation on the discovering 1K5 — two hardware findings and a working fix, all from this morning: Finding 1: waiting doesn't wake the pack. The first 0.9.5 design (hold at battery-zero, wait for the register) engaged cleanly — pending accepted, no fault, no flap — but the new Finding 2: the register is dead even under current flow. A 200 W probe charge landed — the battery demonstrably charged at probe level — while the register stayed 0. In the idle-at-floor state the register doesn't lag; it lies. Register-gated escalation can never fire. (This also retroactively explains v0.2.0's happy 4.5 kW night import: the pack takes what's asked; only the register claims otherwise.) The fix that ships in this PR: ramp on measured uptake. When the register sleeps, the request grows 500 W per poll while the battery follows (half the current request as the follow threshold), decays one step on stalls, never exceeds the commanded target, and hands over to the register path the moment the register actually rises. Patience only counts time without uptake — a charging pack is success in progress. Measured result (2026-08-20 08:34 CEST, SoC 11%, register flat 0 throughout): commanded +2000 W → battery climbed 721 → 1119 → 1560 → 1938 → ~2000 W in ~90 s and held around target (± cloud-driven scatter of the documented one-poll-lag kind; mean on target). Three new harness tests cover the ramp, the stall decay, and uptake-blocks-timeout; 73 total pass. The candidate build runs as the local override on the discovering site for the natural planner slots tonight. Review and merge at will — the HA-side alert tiering already keeps the operator's phone quiet meanwhile. 🤖 Generated with Claude Code |
Follow-up to #96, from the same live site within a day of the 0.9.4 stable promotion.
What happened. The night refusal loop is fixed — and reappeared in daylight. Two incidents (2026-08-19 11:32 and 2026-08-20 07:48, both at 11–14% SoC with the battery idle at the SoC floor under weak PV): the BMS limit read below the 250 W floor with the sun up, the daylight branch refused instantly, the host re-commanded every 5 minutes, and the fault flapped indefinitely — one operator page per throttle window, forever.
The corrected model.
Pwr_limit_Bat_upfollows the battery's activity, not its capability. A battery that has sat idle dozes off and reports no headroom until a session asks and waits — at night because the whole inverter stands by, in daylight because the pack itself idles at the floor. The day/night split in 0.9.4 was treating a property of the battery as a property of the sun.Fix. The pending-accept path is now universal: a floor-level limit always accepts the charge as pending — battery held at zero (night: AC = 0; daylight: AC = pv, PV passes to house + grid), session alive, limit re-read every poll, true setpoint applied the moment it rises, 3-minute patience before treating the refusal as genuine (full/cold pack costs at most 3 minutes of held-zero before native self-use resumes). Two new daylight harness tests mirror the night trio; 70 total pass.
Also corrects the incident dates the 0.9.4 notes carried (August, not September — my error, caught against the repository clock).
The discovering site runs the HA-side symptom (fault-flap paging) tiered and throttled meanwhile; this PR removes the flap's cause. Local-override validation on the live site to follow tonight's planner slots — same protocol as #96: verification notes get the measured result before this merges.
🤖 Generated with Claude Code