# 2026-04-26 (afternoon) — LVX6048 parallel-mode commissioning Got the two LVX6048 inverters operationally paralleled, sharing battery charge from the EG4 LP4 v2 bank symmetrically. Several discoveries about the firmware's parallel-state reporting along the way, plus a couple of small patches. ## What happened 1. **Firmware parity (main CPU): achieved.** Pre-flash main versions were 06303 (unit 1) and 06440 (unit 2). User flashed both to **06306** using the MPP Solar `InfiniVMasterCPU_Reflash` tool. Active fault 71 ("Parallel version different") cleared. 2. **Slave-CPU firmware: still skewed but benign.** Slaves remain 06126 / 06021. The vendor's `LVX6048 FW63.06.zip` *does* include a `dsp.hex` slave bin, but the operational evidence (load-sharing, matched battery V, no faults, master/slave handshake completing) indicates the slave delta is not blocking parallel function on this firmware family. **Not flashing the DSPs** — filed for the record only. 3. **Battery wiring + commissioning.** Both inverters tied to the same 3× EG4 LP4 v2 100 Ah bank (300 Ah at 51.2 V nominal). After fault 83 ("Parallel battery voltage detect different") cleared on first battery-connected boot, both inverters entered MOD `06` and began sharing the charge load (~55 A each, ~110 A combined ≈ 0.37 C). 4. **MCHGC mismatch (100 A vs 60 A) → fixed.** Unit 1 was at 100 A — above the PI18 `MCHGC` setter's 80 A ceiling, so it had to be set via the LCD (Program 02). User dropped unit 1 to 60 A so both match. Confirmed via `flash.py compare` (12/12 settings match). 5. **Patch (g) tweak — `outputformats/hass.py`** *(unrelated to parallel work but lives in the same patch tree).* No change here today; the morning's cleanup is in commit `f771ec2`. 6. **Patch (h) — `pi18.py` MOD decoder.** Inverter started reporting MOD code `06` after batteries connected; the existing decoder only knew 00..05 and crashed (`KeyError: '06'`). Added `"06": "Charge"`. The "Charge" label is an educated guess based on observed behavior (active charging, no AC out); revisit if it turns up in unrelated states. 7. **`parallel_instance_number` decoder fixed.** The GS/PGS field is the parallel-instance index per the PI18 spec (0 = master, 1+ = slaves), not a 2-value flag — but powermon upstream (and our patch) was decoding it as `["Not valid", "valid"]`, which made the master appear as "Not valid" in HA. Replaced with an `OPTION` decoder labeling each index ("instance 0 (master)", "instance 1", ...) in both GS field 27 and PGS field 0. `flash.py sync-check` updated accordingly: removed the false-positive "GS parallel_instance_number = Not valid" issue, replaced with index-collision and no-master checks. 8. **`lvx-resolve-links` now auto-runs on USB hot-plug.** Added an `ACTION=="add"` udev rule for vendor 0665 / product 5161 that `RUN+=`s `systemctl --no-block restart lvx-resolve-links.service powermon.service powermon2.service`. Powermon's `Requires=` / `After=` already serialize the chain. Added a retry loop to the resolver script (poll up to ~10 s for both expected serials) so a single hidraw appearing slightly before its sibling doesn't leave a symlink missing. Tested via `udevadm trigger --action=add --subsystem-match=hidraw`: all three services restarted in lock-step and symlinks rewrote cleanly. 9. **Battery profile YAML for the bank.** Created `lvx-flash/profiles/eg4-lp4-v2.yaml` capturing the conservative off-grid LFP policy (USER mode, bulk 56.4 V / float 54.0 V, cutoff 48.0 V, stop-charge 54.0 V). Live state already matches — applying would be a no-op. Kept as the canonical record of the chosen policy. 10. **Sanity dumps** — `2026-04-26-lvx6048_{1,2}-dump` capture per-unit settings post-commissioning. Useful as a baseline for diff-on-suspect. 11. **Battery side: re-discovered that EG4 LP4 v2's inter-pack daisy-chain silences slave packs.** User had wired the inter-pack `Link-In/Link-Out` chain earlier in the day; it elects a master and demotes slaves on their independent RS485 ports. Pulling the chain restored all three packs to MQTT immediately (all reporting 54.62 V agreement). Daemon needed no change. Memorized for next time. ## Net effect | Metric | Before | After | |---|---|---| | Main-CPU firmware | 06303 / 06440 | **06306 / 06306** ✓ | | Slave-CPU firmware | 06126 / 06021 | unchanged (benign) | | Active fault 71 | yes | cleared | | Active fault 83 | n/a (no battery) | cleared | | MCHGC delta | 100 A vs 60 A | 60 A / 60 A ✓ | | Settings parity | mismatch | 12/12 match | | Charge-current sharing | n/a | 55 A / 57 A symmetric | | Battery V agreement | n/a | 55.1 V / 55.1 V identical | | `parallel_instance_number` | "Not valid" / "valid" (master mislabeled) | "instance 0 (master)" / "instance 1" | | MOD 06 crash on sync-check | yes | fixed | | Hot-plug symlink recovery | manual `systemctl restart` | automatic via udev `RUN+=` | ## Files touched ``` M LVX6048/powermon-patches/pi18.py (MOD 06 -> "Charge"; parallel_instance_number decoder fix) M LVX6048/lvx-flash/flash.py (parallel_instance_number index semantics; new sync-check rules) M LVX6048/bin/lvx-resolve-links (retry loop for hot-plug race) M LVX6048/etc/udev/rules.d/99-lvx6048.rules (ACTION=="add" RUN+= cascade) A LVX6048/2026-04-26-lvx6048_1-dump (post-commissioning baseline) A LVX6048/2026-04-26-lvx6048_2-dump (post-commissioning baseline) A LVX6048/lvx-flash/profiles/eg4-lp4-v2.yaml (canonical battery profile) A LVX6048/2026-04-26-parallel.md (this file) ``` ## How to verify ```bash sudo systemctl stop powermon.service powermon2.service sudo systemctl restart lvx-resolve-links.service # always run after inverter power-cycle /home/noise/solar/LVX6048/lvx-flash/flash.py sync-check \ --device-a /dev/lvx6048-1 --device-b /dev/lvx6048-2 sudo systemctl start powermon.service powermon2.service ``` Pass criteria post-commissioning: - main fw 06306 on both - `mode=06` (Charge) or `mode=03` (Battery) or `mode=05` (Hybrid) — i.e. healthy operating modes, no `04` (Fault) - `fault=No fault` on both - both `parallel_*` values present (one as master/0, one as slave/1) - battery V agreement within ~0.2 V - charge currents within ~5 A symmetric (when both are charging) ## Loose ends / next pass 1. update `LVX6048/README.md` "Next steps" section to reflect that parallel commissioning + decoder + hot-plug fixes are done, and the slave-firmware delta is intentionally unrepaired (benign) 2. (optional) verify MOD 06 label by observing in different states 3. (optional) decode remaining PGS fields now that values are meaningful 4. (optional, longer horizon) closed-loop BMS comms via the dedicated pack→inverter CAN port; defer until open-loop has been stable for a week and we can baseline SoC accuracy