Files
shaggy-solar/LVX6048/README.md
2026-04-24 16:34:10 -04:00

7.7 KiB
Raw Blame History

LVX6048 → Home Assistant

Reproducible install package for monitoring 2× MPP Solar LVX6048 inverters over USB-HID (PI18) via powermon, publishing to a Home Assistant MQTT broker with HA auto-discovery.

What's in the box

LVX6048/
├── README.md                     ← start here
├── Install.md                    ← detailed walkthrough (what install.sh does)
├── Monitoring.md                 ← background / design notes
├── install.sh                    ← one-shot installer (idempotent, safe to re-run)
│
├── etc/                          mirror of target system paths
│   ├── udev/rules.d/99-lvx6048.rules
│   └── systemd/system/
│       ├── lvx-resolve-links.service
│       ├── powermon.service
│       ├── powermon2.service
│       ├── powermon.service.d/10-resolver.conf
│       └── powermon2.service.d/10-resolver.conf
│
├── config/powermon/              lands at ~/.config/powermon/ (mode 600)
│   ├── powermon.yaml             ← unit #1 — edit MQTT creds before deploying
│   └── powermon2.yaml            ← unit #2 — edit MQTT creds before deploying
│
├── bin/
│   └── lvx-resolve-links         ← installed as /usr/local/sbin/lvx-resolve-links
│                                   (install.sh rewrites the shebang to the uv-installed python)
│
├── powermon-patches/             ← drop-in files for the uv tool install
│   ├── README.md                 ← what each patch does + upgrade path
│   ├── pi18.py, usbport.py, mqttbroker.py,
│   └── port_config_model.py, ports_init.py
│
├── lvx-flash/                    ← settings-profile CLI
│   ├── flash.py                  ← dump / diff / apply / compare / sync-check
│   ├── README.md
│   └── profiles/current.yaml
│
└── smoketest/                    ← adhoc test configs (one-off powermon -C usage)
    ├── console.yaml
    └── smoketest.yaml

Quick start (reproducing on a fresh machine)

# 1. Clone / scp this folder into place (e.g. /home/<user>/solar/LVX6048)
cd ~/solar/LVX6048

# 2. Install uv if not already: https://docs.astral.sh/uv/
# 3. Run the installer
./install.sh

# 4. Edit the two things install.sh warns about:
#    a. ~/.config/powermon/powermon{,2}.yaml — MQTT broker IP / user / password
#    b. /usr/local/sbin/lvx-resolve-links    — SERIAL_UNIT_1 / SERIAL_UNIT_2 (see below)
#       lvx-flash/flash.py                   — same two constants

# 5. Capture each inverter's PI18 serial (with services stopped):
sudo systemctl stop lvx-resolve-links.service powermon.service powermon2.service
for d in /dev/hidraw0 /dev/hidraw1; do
    TMP=$(mktemp --suffix=.yaml)
    printf 'loop: once\ndevice:\n  name: probe\n  port: {type: usb, path: %s, protocol: PI18}\ncommands:\n  - {command: ID, trigger: {loops: 1}}\n' "$d" > "$TMP"
    echo "=== $d ==="
    ~/.local/bin/powermon -C "$TMP" 2>&1 | grep serial_number
    rm -f "$TMP"; sleep 2
done
# Edit SERIAL_UNIT_{1,2} in /usr/local/sbin/lvx-resolve-links and lvx-flash/flash.py,
# then:
sudo systemctl start lvx-resolve-links.service powermon.service powermon2.service

How the pieces fit together

┌─────────────────────────┐     ┌─────────────────────────┐
│ LVX6048 #1 (USB-HID)    │ ──▶ │ /dev/hidraw{0|1}        │
│ LVX6048 #2 (USB-HID)    │ ──▶ │ (vid:pid 0665:5161)     │
└─────────────────────────┘     └──────────┬──────────────┘
                                           │
                                           │  (99-lvx6048.rules → group=dialout)
                                           │
                                           ▼
                          ┌──────────────────────────────────┐
                          │ lvx-resolve-links.service        │
                          │ (oneshot, runs before powermon)  │
                          │                                  │
                          │  probes each hidraw w/ PI18 ID   │
                          │  creates /dev/lvx6048-{1,2}      │
                          │  symlinks keyed to serial        │
                          └──────────┬───────────────────────┘
                                     │
                                     │ After= / Requires=
                                     ▼
                          ┌──────────────────────────────────┐
                          │ powermon.service  (unit #1)      │
                          │ powermon2.service (unit #2)      │
                          │                                  │
                          │  poll GS / MOD / PIRI / ET       │
                          │  publish to HA auto-discovery    │
                          │  topics under homeassistant/*    │
                          └──────────┬───────────────────────┘
                                     │  MQTT (port 1883)
                                     ▼
                          ┌──────────────────────────────────┐
                          │ Home Assistant Mosquitto broker  │
                          │ ~29 auto-discovered sensors/unit │
                          └──────────────────────────────────┘

Separate from the monitoring pipeline, lvx-flash/ is a manual settings tool: dump the inverter's current config into a YAML profile, diff against a target profile, apply changes safely (stops powermon, writes via PI18 setters, verifies via PIRI readback). Also supports compare (diff live settings between two inverters) and sync-check (verify parallel-stack health).

Cable moves

Identification is PI18-serial-based, so moving USB cables between hub ports never requires config edits. After any cable shuffle:

sudo systemctl restart lvx-resolve-links.service powermon.service powermon2.service

Replacing an inverter

When a unit is swapped, capture its new PI18 serial (see step 5 of Quick start) and update the two SERIAL_UNIT_* constants in:

  • /usr/local/sbin/lvx-resolve-links
  • ~/solar/LVX6048/lvx-flash/flash.py

then restart the three services.

Next steps / not done

  • Firmware parity: on this dev stack, unit #1 is at main=06303/slave=06126 and unit #2 is at 06440/06021. Parallel operation requires matching firmware (fault code 71 "Parallel version different") — the sync kit's cables are wired correctly, but the inverters won't phase-lock until both CPUs match. Firmware upload is not part of this package (MPP Solar Windows-only tool).
  • PGS field layout: the LVX6048-specific 30-field PGS response layout is only partially decoded in powermon-patches/pi18.py. The key fields (parallel_valid, fault_code, grid_hz, ac_output_voltage) are named; the rest are exposed as raw strings.
  • Control / set commands via HA: PI18 setters (POP, PCP, MCHGC, MUCHGC, PF) are implemented in lvx-flash/flash.py for offline use, but aren't exposed as HA button/select entities. Deferred until monitoring has been stable for at least a week and firmware parity is restored.