6.9 KiB
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
-
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_Reflashtool. Active fault 71 ("Parallel version different") cleared. -
Slave-CPU firmware: still skewed but benign. Slaves remain 06126 / 06021. The vendor's
LVX6048 FW63.06.zipdoes include adsp.hexslave 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. -
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
06and began sharing the charge load (~55 A each, ~110 A combined ≈ 0.37 C). -
MCHGC mismatch (100 A vs 60 A) → fixed. Unit 1 was at 100 A — above the PI18
MCHGCsetter'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 viaflash.py compare(12/12 settings match). -
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 commitf771ec2. -
Patch (h) —
pi18.pyMOD decoder. Inverter started reporting MOD code06after 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. -
parallel_instance_numberdecoder 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 anOPTIONdecoder labeling each index ("instance 0 (master)", "instance 1", ...) in both GS field 27 and PGS field 0.flash.py sync-checkupdated accordingly: removed the false-positive "GS parallel_instance_number = Not valid" issue, replaced with index-collision and no-master checks. -
lvx-resolve-linksnow auto-runs on USB hot-plug. Added anACTION=="add"udev rule for vendor 0665 / product 5161 thatRUN+=ssystemctl --no-block restart lvx-resolve-links.service powermon.service powermon2.service. Powermon'sRequires=/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 viaudevadm trigger --action=add --subsystem-match=hidraw: all three services restarted in lock-step and symlinks rewrote cleanly. -
Battery profile YAML for the bank. Created
lvx-flash/profiles/eg4-lp4-v2.yamlcapturing 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. -
Sanity dumps —
2026-04-26-lvx6048_{1,2}-dumpcapture per-unit settings post-commissioning. Useful as a baseline for diff-on-suspect. -
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-Outchain 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
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) ormode=03(Battery) ormode=05(Hybrid) — i.e. healthy operating modes, no04(Fault)fault=No faulton 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
- 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) - (optional) verify MOD 06 label by observing in different states
- (optional) decode remaining PGS fields now that values are meaningful
- (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