Add solar-morning-run controller (solar-only calibration default)

Unattended morning runner for the calibration top-off. DEFAULT is solar-only
@ 60A: no setter, reads telemetry, weather-gates (PV<4kW by 10:30 -> abort),
monitors the charge with cell>3.65V / temp>45C aborts, verifies all 6 packs
re-anchor to 100%. Validated end-to-end via --dry-run against live HA.

Key firmware finding baked in (confirmed live): MCHGC is LOCKED while charging
(NAKs even in device_mode 'Battery' when charger_status='charging') -- so the
80A throttle test is opt-in (THROTTLE=1), gated on a true pre-charge idle
window, with retry-on-revert and a guaranteed-safe fallback (cap stays 80A
until idle if revert NAKs). No clean noon A/B is possible; documented as such.

Also handles the HA pack-temperature unit trap (entities report degF; the
script reads unit_of_measurement and converts to degC for the safety check).

REFERENCE: documented the MCHGC charging-lock under known issues.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-25 08:07:49 -04:00
parent 4d6c6c109b
commit 34d34f6e6c
2 changed files with 234 additions and 0 deletions

View File

@@ -130,6 +130,15 @@ MQTT — compute them yourself from the raw entities when working off the Pi.
Daily kWh must come from HA recorder or ET deltas.
- **Parallel cluster**: changing inverter settings on only one unit risks fault 86
(desync). `lvx-control` always mirrors to both — that's why setters go through it.
- **MCHGC (max_charging_current) is firmware-LOCKED while charging** — confirmed live
2026-06-25: a cap change NAKs ("Failed") on BOTH units whenever `mppt1_charger_status`
= `charging`, even though `device_mode` still reads `Battery`. So the cap is only
settable in a true pre-charge idle window (dawn) and revertible only once charging
stops. Detect charging via `charger_status`, NOT `device_mode`. This is why
`solar-morning-run` defaults to solar-only @ 60 A and gates the 80 A throttle behind
an idle check. Same lock applies via `flash.py` (it's an inverter-side lock).
- **MCHGC `0`/Full equivalent — see** `battery_re_discharge_voltage` gotcha in the
calibration notes (`stop_charge_voltage` is really re-discharge; firmware NAKs 0).
## Action policy for these skills