From 5e175d4d0b3501828259a53d864b79bd7d732e48 Mon Sep 17 00:00:00 2001 From: noise Date: Wed, 24 Jun 2026 14:14:35 -0400 Subject: [PATCH] Fix calibration grid-assist lever: firmware NAKs stop_charge=0/Full MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Live run 2026-06-24: flash.py apply NAK'd BUCD480,000 on both inverters — the firmware rejects stop_charge_voltage=0 ("Full"). flash.py aborts on first setter failure, so nothing changed and the cluster stayed in sync (verified). The field flash.py calls stop_charge_voltage is actually the inverter's battery_re_discharge_voltage (HA: sensor.lvx6048_*_battery_re_discharge_voltage): the V at which loads switch back to battery after grid charging. 54.0 tops grid charge to ~54V; raising to 56.0 is the corrected (but UNVALIDATED) lever and may band-oscillate rather than hold absorption. - calibration profile: 0 -> 56.0, with the finding documented. - skill: solar-only is now the RECOMMENDED/known-good method; grid-assist demoted to advanced/unvalidated with a mandatory diff-preview gate. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/skills/calibration-charge/SKILL.md | 23 ++++++++++++------ .../profiles/eg4-lp4-v2-calibration.yaml | 24 +++++++++++++------ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/.claude/skills/calibration-charge/SKILL.md b/.claude/skills/calibration-charge/SKILL.md index 34044f3..2ec26f5 100644 --- a/.claude/skills/calibration-charge/SKILL.md +++ b/.claude/skills/calibration-charge/SKILL.md @@ -48,14 +48,23 @@ Record and check: - **Forecast/grid**: solar-only needs a sunny low-load day; grid-assist works anytime. ## 2. Choose the method (ask the user) -- **Solar-only (no setting change, free):** on a sunny, low-load day the bank reaches - bulk 56.4 V on its own (the 54 V cap only gates GRID charging, not solar). Just - monitor §4 and verify §5. Best when weather cooperates; no flash needed — skip §3. -- **Grid-assist (reliable, any weather):** temporarily lift the grid-charge ceiling so - grid finishes the top-off. Needs the setter change in §3. Use this if it's cloudy or - a full charge hasn't happened in a while. +- **Solar-only — RECOMMENDED (no setting change, free, known-good):** on a sunny, + low-load day with a full day ahead, solar drives the bank through the full CC/CV + curve to bulk 56.4 V and holds absorption on its own — exactly the clean termination + the BMS needs to re-anchor. No flash, no risk. Just monitor §4 and verify §5; skip §3. + This is the method to default to. +- **Grid-assist — ADVANCED / UNVALIDATED:** the field flash.py calls + `stop_charge_voltage` is really `battery_re_discharge_voltage`; the firmware **NAKs + `0`/"Full"** (confirmed 2026-06-24 — both units rejected `BUCD480,000`). The corrected + lever raises it 54.0 → 56.0 so grid charges higher, but it may band-oscillate near + 56 V instead of holding a clean absorption, so it is **not proven** to re-anchor. + Only use as a supervised experiment when solar can't reach full and you accept it + may not fully work. Needs §3. -## 3. Grid-assist: apply the calibration profile (USER-CONFIRMED setter change) +## 3. Grid-assist (ADVANCED): apply the calibration profile (USER-CONFIRMED setter change) +Run `flash.py diff` FIRST and confirm the ONLY change is `stop_charge_voltage 54.0 -> +56.0` before applying. If any apply NAKs, the cluster is unchanged (flash.py aborts on +first failure) — fall back to solar-only. Mirror to BOTH inverters (parallel cluster — mismatched settings throw fault 86). `flash.py apply` stops powermon for exclusive USB, so MQTT telemetry pauses briefly. ```bash diff --git a/LVX6048/lvx-flash/profiles/eg4-lp4-v2-calibration.yaml b/LVX6048/lvx-flash/profiles/eg4-lp4-v2-calibration.yaml index 73bd536..f93c5c0 100644 --- a/LVX6048/lvx-flash/profiles/eg4-lp4-v2-calibration.yaml +++ b/LVX6048/lvx-flash/profiles/eg4-lp4-v2-calibration.yaml @@ -7,11 +7,20 @@ # / high-load stretches the bank may go weeks without a full charge and the coulomb # counters drift (e.g. pack 6 read 76% while physically at ~53% on 2026-06-24). # -# The ONLY change vs the canonical eg4-lp4-v2.yaml is: -# stop_charge_voltage: 54.0 -> 0 (= "Full"; remove the grid-charge ceiling so a -# full charge can complete even without strong sun) -# bulk_voltage stays 56.4 (the absorption target). Solar already charges past 54 V on a -# good day; this profile just lets GRID finish the top-off when solar can't. +# !!! 2026-06-24 FINDING — grid-assist lever corrected, still UNVALIDATED !!! +# The original idea (stop_charge_voltage: 0 = "Full") was REJECTED by the firmware: +# `flash.py apply` got an inverter NAK on `BUCD480,000` on BOTH units (no change made). +# The field flash.py calls `stop_charge_voltage` is really the inverter's +# **battery_re_discharge_voltage** (HA: sensor.lvx6048_*_battery_re_discharge_voltage) — +# the voltage at which the inverter switches loads back to battery after grid charging. +# At 54.0 V, grid tops the bank only to ~54 V. Raising it (below) lets grid charge +# higher, BUT it may band-oscillate near the setpoint rather than hold a clean +# absorption, so it's NOT guaranteed to give the full-charge termination the BMS needs +# to re-anchor. SOLAR-ONLY is the known-good method (solar follows the full CC/CV curve +# to bulk + absorption); use this grid profile only as a supervised experiment. +# +# Corrected (candidate) change vs canonical: stop_charge_voltage 54.0 -> 56.0 (was 0). +# bulk_voltage stays 56.4 (absorption target). # # USE: this is a TEMPORARY profile driven by the `calibration-charge` skill. Apply to # BOTH inverters, run the full charge, verify all 6 packs hit 100%, then REVERT to @@ -35,8 +44,9 @@ battery_type: USER cutoff_voltage: 48.0 stop_discharge_voltage: 48.0 -# 0 = Full — let grid charge all the way to bulk (the calibration lever). -stop_charge_voltage: 0 +# re-discharge voltage. 54.0 (canonical) tops grid charge to ~54 V; 56.0 lets grid +# charge higher. NOT 0 — firmware NAKs 0/"Full". Range 48.0..58.0. UNVALIDATED lever. +stop_charge_voltage: 56.0 bulk_voltage: 56.4 float_voltage: 54.0