155 lines
7.7 KiB
Markdown
155 lines
7.7 KiB
Markdown
|
|
# LVX6048 → Home Assistant
|
|||
|
|
|
|||
|
|
Reproducible install package for monitoring 2× MPP Solar LVX6048 inverters over
|
|||
|
|
USB-HID (PI18) via [`powermon`](https://github.com/jblance/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)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 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:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
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.
|