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

11 KiB
Raw Blame History

LVX6048 Monitoring & Control via Home Assistant

Integration plan for monitoring (and eventually controlling) 2x LVX6048 inverters from Home Assistant via a Raspberry Pi running a Python poller that publishes to MQTT.

Continue dev from the Raspberry Pi.

Architecture

  [LVX6048 #1] ──USB─┐
                     ├──► [Raspberry Pi] ──MQTT──► [Home Assistant]
  [LVX6048 #2] ──USB─┘    (mpp-solar/powermon     (auto-discovers
                           Python daemon,          ~40 entities
                           systemd service)        per inverter)

Why USB (not RS485)

The LVX6048 is an MPP Solar / Voltronic-family unit. Its documented, supported comm path is USB-HID speaking the PI18 protocol (some firmware revisions also accept PI30). The RS485 port exists on the hardware but is undocumented for external monitoring on this model — it's primarily intended for parallel/BMS comms. Use USB.

Why mpp-solar

jblance/mpp-solar is the canonical Python package for this inverter family. It ships:

  • PI18 / PI18LVX / PI30 / PI30MAX protocol drivers (all known query + set commands)
  • A powermon daemon for continuous polling
  • Built-in MQTT publisher with Home Assistant auto-discovery topic format — no HA YAML needed, entities appear automatically

Hardware Checklist

  • Raspberry Pi (Pi 4 or Pi 5 recommended; Pi 3B+ works) running Raspberry Pi OS 64-bit
  • microSD card (32GB+) or USB SSD
  • 2x USB-A to USB-B cables (one per inverter; ~3ft typical — keep short, USB-HID is not spec'd for long runs)
  • Pi physically located near the inverter cabinet
  • Ethernet (preferred) or WiFi to reach the HA MQTT broker
  • Existing MQTT broker running on HA (confirmed operational)

Step 1 — Base Pi Setup

sudo apt update && sudo apt upgrade -y
sudo apt install -y python3-pip python3-venv pipx git
pipx ensurepath

Reboot (or exec $SHELL) so pipx PATH takes effect.

Step 2 — Install mpp-solar

pipx install mpp-solar
# verify
mpp-solar --version
mpp-solar --listProtocols

Expect PI18, PI18LVX, PI18SV, PI30, PI30MAX in the protocol list.

Step 3 — Plug in Inverters & Identify Them

Connect inverter #1 first, alone, and run:

ls -l /dev/hidraw*
lsusb
dmesg | tail -20

Note the /dev/hidraw* device that appeared and the USB VID:PID (typical MPP Solar is 0665:5161 — confirm on your unit).

Grab the serial number for a stable udev rule:

udevadm info -a -n /dev/hidraw0 | grep -i serial | head -3

Write down SERIAL_A. Unplug #1, plug in #2, repeat to get SERIAL_B.

Step 4 — Smoke Test

With inverter #1 still plugged in, query it directly:

mpp-solar -p /dev/hidraw0 -P PI18 -c GS

GS is the PI18 "General Status" query. Expected output: battery voltage, SoC, PV watts, load watts, grid voltage, inverter mode, etc. If PI18 returns gibberish or CRC errors, try PI30:

mpp-solar -p /dev/hidraw0 -P PI30 -c QPIGS

Whichever protocol returns clean data → that's the one to use in the config below. Record which protocol worked.

Also grab rated info once:

mpp-solar -p /dev/hidraw0 -P PI18 -c PIRI    # PI18 rated info
# or
mpp-solar -p /dev/hidraw0 -P PI30 -c QPIRI   # PI30 rated info

Step 5 — Stable Device Names (udev)

Without this, /dev/hidraw0 and /dev/hidraw1 can swap on reboot, and the wrong inverter's data ends up under the wrong entity in HA.

As built on this CM5: the LVX6048 returns no USB serial string, so serial-based matching below is aspirational. We ended up matching by USB hub port instead — see 99-lvx6048.rules and Install.md §2.

Create /etc/udev/rules.d/99-lvx6048.rules:

SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0665", ATTRS{idProduct}=="5161", ATTRS{serial}=="SERIAL_A", SYMLINK+="lvx6048-1", MODE="0660", GROUP="dialout"
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0665", ATTRS{idProduct}=="5161", ATTRS{serial}=="SERIAL_B", SYMLINK+="lvx6048-2", MODE="0660", GROUP="dialout"

Replace SERIAL_A / SERIAL_B and the VID:PID with the real values from Step 3. Then:

sudo usermod -aG dialout $USER
sudo udevadm control --reload-rules
sudo udevadm trigger
ls -l /dev/lvx6048-*

Both symlinks should be present. Log out / back in so the dialout group applies.

Step 6 — powermon Config

As built: the ports: (plural) schema shown below does not work with current powermon — its config model allows exactly one device: per file. We ship one config file per inverter (powermon.yaml, powermon2.yaml) and run two systemd units. See Install.md §46.

Create ~/.config/powermon/powermon.yaml (adjust MQTT creds and protocol name to match Step 4):

device:
  name: lvx6048_pair
  id: solar_lvx6048

mqttbroker:
  name: <HA_MQTT_BROKER_IP>
  port: 1883
  username: <MQTT_USER>
  password: <MQTT_PASSWORD>
  adhoc_topic: powermon/adhoc
  adhoc_result_topic: powermon/adhoc/results

api:
  enabled: false

daemon:
  type: systemd
  keepalive: 60

ports:
  - name: lvx1
    type: usb
    path: /dev/lvx6048-1
    protocol: PI18      # confirmed in Step 4
    commands:
      - command: GS
        trigger: { every: 5 }
        outputs: { name: mqtt_ha, type: hass, tag: lvx6048_1 }
      - command: PIRI
        trigger: { every: 300 }
        outputs: { name: mqtt_ha, type: hass, tag: lvx6048_1 }
      - command: MOD
        trigger: { every: 10 }
        outputs: { name: mqtt_ha, type: hass, tag: lvx6048_1 }
      - command: FWS
        trigger: { every: 30 }
        outputs: { name: mqtt_ha, type: hass, tag: lvx6048_1 }

  - name: lvx2
    type: usb
    path: /dev/lvx6048-2
    protocol: PI18
    commands:
      - command: GS
        trigger: { every: 5 }
        outputs: { name: mqtt_ha, type: hass, tag: lvx6048_2 }
      - command: PIRI
        trigger: { every: 300 }
        outputs: { name: mqtt_ha, type: hass, tag: lvx6048_2 }
      - command: MOD
        trigger: { every: 10 }
        outputs: { name: mqtt_ha, type: hass, tag: lvx6048_2 }
      - command: FWS
        trigger: { every: 30 }
        outputs: { name: mqtt_ha, type: hass, tag: lvx6048_2 }

Command reference (PI18):

  • GS — General Status (voltages, currents, power, SoC, temps) → poll fast
  • PIRI — Protocol / Rated Info (nameplate values) → poll slow
  • MOD — Operating Mode (Grid / Battery / Fault / Standby) → poll medium
  • FWS — Fault / Warning Status → poll medium
  • ET — Total Energy (lifetime kWh) → optional, add with every: 60
  • ED — Daily Energy → optional

Run it in the foreground once to confirm MQTT is flowing:

powermon -C ~/.config/powermon/powermon.yaml

In Home Assistant, go to Settings → Devices & Services → MQTT — two new devices (lvx6048_1, lvx6048_2) should appear with all their sensors auto-discovered.

Step 7 — systemd Service

Create /etc/systemd/system/powermon.service:

[Unit]
Description=powermon LVX6048 → MQTT bridge
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=pi
Group=dialout
ExecStart=/home/pi/.local/bin/powermon -C /home/pi/.config/powermon/powermon.yaml
Restart=on-failure
RestartSec=10

# Tolerate USB dropouts / HA broker restarts
StartLimitIntervalSec=300
StartLimitBurst=10

[Install]
WantedBy=multi-user.target

Adjust User= / paths if not running as pi. Enable:

sudo systemctl daemon-reload
sudo systemctl enable --now powermon.service
systemctl status powermon.service
journalctl -u powermon.service -f

Step 8 — Home Assistant Dashboard

Entities auto-appear. Minimum useful Lovelace card:

type: entities
title: Solar System
entities:
  - sensor.lvx6048_1_battery_capacity       # %
  - sensor.lvx6048_1_battery_voltage        # V
  - sensor.lvx6048_1_pv_input_power         # W
  - sensor.lvx6048_1_ac_output_active_power # W
  - sensor.lvx6048_1_grid_voltage           # V
  - sensor.lvx6048_1_inverter_heat_sink_temperature
  - sensor.lvx6048_1_working_mode
  - sensor.lvx6048_2_battery_capacity
  - sensor.lvx6048_2_pv_input_power
  - sensor.lvx6048_2_ac_output_active_power
  - sensor.lvx6048_2_working_mode

Entity IDs will reflect the tag: values from the config. Exact names depend on protocol driver — check the MQTT integration page.

Recommended extras:

  • Energy dashboard — map ET (total lifetime energy) as a solar production source
  • Automation: alert when working_mode changes to Fault on either unit
  • Utility meter helpers on ac_output_active_power for daily/weekly kWh

Control (Deferred)

Once monitoring is stable, control commands are available via the same library. PI18 set commands include:

  • POP — Output source priority (SUB / SBU / etc.)
  • PCP — Charger priority (Solar first / Solar+Utility / only Solar)
  • MCHGC — Max total charging current
  • MUCHGC — Max utility charging current
  • PF — Restore defaults (careful)

Exposed in HA as button/select entities via powermon's MQTT command topic. Plan this as a separate phase after at least a week of stable monitoring data.

Troubleshooting

Symptom Likely cause Fix
Permission denied on /dev/hidraw* User not in dialout sudo usermod -aG dialout $USER, re-login
CRC errors / garbled output Wrong protocol selected Try PI30 instead of PI18 (or vice versa)
Device disappears after reboot udev serial mismatch Re-check udevadm info -a, verify serial string
Symlinks swap between units Two units report same serial Fall back to KERNELS=="1-1.2" USB-port matching
HA entities don't appear MQTT discovery disabled or wrong prefix Verify discovery: true in HA MQTT integration; default prefix is homeassistant/
Entities appear but never update powermon service not actually running journalctl -u powermon.service -n 100
One inverter works, other doesn't Parallel-mode RS232 quirk Query the master unit; the slave may not respond to USB queries while linked

Parallel-mode caveat

The 2x LVX6048s are wired in parallel (per README.md). In parallel mode, some MPP Solar firmware only responds to USB/PI commands on the master unit — the slave echoes the master's data or returns errors. If Step 4 smoke tests show one unit timing out, check the LCD to see which is master. If only the master responds, a single poller gives you combined system data; per-unit telemetry may require the parallel/sync RJ45 cable's side-channel (undocumented) or firmware that doesn't gate slave comms.

Recommendation: do Step 4 on each inverter individually (unplug parallel comm cable, query via USB, replug) to confirm both respond. Then test again with parallel cable connected.

References