# lvx-flash Apply declarative YAML settings profiles to an LVX6048 inverter via PI18. Reuses the patched `powermon` install at `~/.local/share/uv/tools/powermon/` — the shebang in `flash.py` points there, so no extra setup is needed. ## Commands ```bash # 1. Snapshot the inverter's current settings into an editable profile. ./flash.py dump --out profiles/current.yaml # 2. Copy/edit. Preview the diff against the live device at any time. ./flash.py diff --profile profiles/winter.yaml # 3. Apply. The tool stops powermon.service for the duration, writes each # changed setting via the corresponding PI18 set command, verifies via # PIRI readback, and restarts powermon.service at the end. ./flash.py apply --profile profiles/winter.yaml --confirm # 4. Compare two inverters live (for parallel setups). Exits 0 if identical, # 1 if divergent. Useful as a quick "are the two in sync?" check. ./flash.py compare --device-a /dev/lvx6048-1 --device-b /dev/lvx6048-2 # 5. Runtime sync-check for paralleled units. Reads GS+FWS+MOD+VFW from each # and reports firmware mismatch, parallel-valid flag, active fault codes, # mode mismatch, AC voltage/frequency divergence. Exits 0 on pass, 1 on fail. ./flash.py sync-check --device-a /dev/lvx6048-1 --device-b /dev/lvx6048-2 ``` Device selection on every subcommand: - `--serial SN` (default — uses `SERIAL_UNIT_1` for single-device commands, `SERIAL_UNIT_{1,2}` for pairs) — globs `/dev/hidraw*` and picks the one whose PI18 `ID` matches. Resilient to cable moves. - `--device PATH` — explicit hidraw path, skips auto-resolution. Useful for probing an unknown unit. The known-stack serials are hard-coded as `SERIAL_UNIT_1` / `SERIAL_UNIT_2` constants at the top of `flash.py`; edit them if a unit is replaced. `sync-check` depends on the `FWS` / `PGS` additions to `powermon/protocols/pi18.py`; the `--serial` flow depends on the `UsbPortConfig.serial_number` field addition. Both are described in `Install.md` §5(d)(e). ## Profile schema All keys are optional. Only present keys are applied; the rest are left alone. | key | range / enum | PI18 setter | |----------------------------------|------------------------------------------------------------------|-------------| | `battery_type` | `AGM` \| `FLOODED` \| `USER` | PBT | | `cutoff_voltage` | 40.0 – 48.0 V | PSDV | | `stop_discharge_voltage` | 44.0 – 51.0 V | BUCD (pair) | | `stop_charge_voltage` | 0 (full) or 48.0 – 58.0 V | BUCD (pair) | | `bulk_voltage` | 48.0 – 58.4 V | MCHGV (pair)| | `float_voltage` | 48.0 – 58.4 V (≤ bulk_voltage) | MCHGV (pair)| | `max_charging_current` | 10, 20, 30, 40, 50, 60, 70, 80 A | MCHGC | | `max_utility_charging_current` | 2, 10, 20, 30, 40, 50, 60, 70, 80 A | MUCHGC | | `output_source_priority` | `solar_utility_battery` \| `solar_battery_utility` | POP | | `charger_priority` | `solar_first` \| `solar_and_utility` \| `solar_only` | PCP | | `solar_power_priority` | `battery_load_utility_ac` \| `load_battery_utility` | PSP | | `grid_tie` | `enabled` \| `disabled` | PEI / PDI | Pair settings (BUCD, MCHGV) must have both halves present. ## Safety - `apply` refuses to run without `--confirm`. - Range + consistency validation runs before any write. A failure aborts before touching the inverter. - Each write is followed by a PIRI readback that must match to within 0.05 V. A mismatch aborts. - Settings are applied in an order that's safe for a battery: cutoff → BUCD → MCHGV → currents → priorities → grid-tie mode. - `powermon.service` is stopped for the write window so the two processes don't fight over `/dev/lvx6048-1`, then restarted even if the run aborts. ## Caveats - Parallel setups: PCP / MCHGC / MUCHGC are indexed by parallel unit (the tool sends unit 0 — master). Some firmware only accepts sets on the master; the slave mirrors silently. - `PIRI` reports `max_charging_current` as the effective combined (solar + AC) cap, which can exceed MCHGC's 80 A range. `dump` omits it with a comment when that happens. - Changing `battery_type` while the unit is actively charging is generally allowed by the firmware but not recommended.