Files
noise 8dafce7dfe Docs: reflect this session's findings across the repo
- top-level README.md (new): system overview, subsystem map, skills pointer,
  notable findings.
- eg4battery README/NOTES: 3 -> 6 packs (pack 6 oddball 0x01/115200); SoC drift
  + calibration section; closed-loop comms evaluated and rejected (loses per-pack
  telemetry, no native protocol, doesn't fix drift); how to force a grid charge
  via output-priority SUB.
- LVX6048 README: closed-loop pending item -> resolved decision; new "SoC
  calibration & known firmware quirks" section (POP single-digit/POP01, MCHGC
  charge-lock, re_discharge=re-discharge can't exceed float, PIRI lag, powermon
  adhoc wedge); skills pointer.
- lvx-control README: POP encoding fix, POP crc-but-applies quirk, verify-by-
  behavior, grid-charge-via-SUB usage.
- troubleshoot-inverter skill: corrected the stale "dead string per inverter"
  claim — both strings healthy; low PV is tilt/heat/shade/curtailment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 21:46:02 -04:00
..

lvx-control

Tiny daemon that bridges Home-Assistant-friendly MQTT topics to powermon's adhoc-command queue, so HA buttons / selects / numbers can drive the LVX6048 pair without anyone touching the LCD or the shell.

What it does

HA dashboard (mqtt button)
    │
    │  payload "solar_battery_utility"
    ▼
solar/control/lvx6048/output_priority           (subscribed by lvx-control)
    │
    │  validates against the allow-list, encodes to PI18
    │  e.g. "POP01"  (output source = solar -> battery -> utility)
    ▼
powermon/lvx6048_1/addcommand     ┐  mirrored to BOTH inverters in
powermon/lvx6048_2/addcommand     ┘  the same publish so the parallel
                                     cluster never desyncs (fault 86)
    │
    ▼
powermon services execute the command on each unit; result lands in
powermon/lvx6048_{1,2}/result for HA to confirm

Supported actions

Friendly topic suffix → PI18 setter:

Topic suffix Payload values PI18
output_priority solar_utility_battery | solar_battery_utility POP
charger_priority solar_first | solar_and_utility | solar_only PCP
solar_power_priority battery_load_utility_ac | load_battery_utility PSP
max_charging_current 10,20,30,40,50,60,70,80 (combined solar+AC, A) MCHGC
max_utility_charging_current 2,10,20,30,40,50,60,70,80 (grid-side, A) MUCHGC

Risky setters (battery thresholds, type, output mode, factory reset) are intentionally not exposed here — those should go through lvx-flash/flash.py apply with an explicit profile and confirmation.

Known limitations & quirks

max_charging_current (MCHGC) and max_utility_charging_current (MUCHGC) return Failed whenever the inverter is actively charging (charger_status = charging, even while device_mode reads Battery) — the firmware locks these charge-current setters during charge. Set them only in a pre-charge idle window, or via the LCD (Programs 02 / 11), or lvx-flash/flash.py apply.

Other quirks (confirmed 2026-06-25):

  • POP is single-digit. output_priority=solar_battery_utility must encode as POP1, NOT POP01 — the inverter silently rejects the malformed POP01 (nothing on the result topic, no effect). Fixed in POP_MAP here and in flash.py. If reinstalling, make sure the live /usr/local/bin/lvx-control has the fix.
  • A POP set returns "crc check fails" on the result topic but still applies; PCP returns a clean "Succeeded". So verify a POP change by behavior (device_mode / line_power_direction), not the result string.
  • PIRI readback lags ~5 min — don't trust the *_output_source_priority sensor to confirm a just-issued change; watch the behavior instead.
  • If commands stop landing on the result topic entirely, powermon's adhoc queue has wedged → sudo systemctl restart powermon.service powermon2.service.

Forcing a full grid charge (calibration)

To grid-charge the bank to full (e.g. SoC calibration on a cloudy day), set output_prioritysolar_utility_battery (SUB) so the inverter runs loads off grid and charges the battery to full, plus charger_prioritysolar_and_utility. Revert to solar_battery_utility + solar_first when done. Automated and safety-monitored by ../../.claude/skills/lib/grid-cal-monitor.

Track the result topic to see the actual outcome of each command.

Quick test

# subscribe to results in another terminal
mosquitto_sub -h <broker> -u mqtt -P <pass> -v \
    -t 'powermon/lvx6048_1/result' \
    -t 'powermon/lvx6048_2/result'

# fire a control command
mosquitto_pub -h <broker> -u mqtt -P <pass> \
    -t 'solar/control/lvx6048/charger_priority' \
    -m 'solar_first'

You should see the encoded PCP0,0 show up at the inverters' result topics within ~1 second, and the existing PIRI sensor in HA will reflect the new state on the next 5-minute cycle.

Files

lvx-control/lvx-control               <-- single-file Python (PEP-723 deps)
lvx-control/README.md                 <-- this file
etc/systemd/system/lvx-control.service

install.sh copies the script to /usr/local/bin/lvx-control and enables the systemd unit. Broker credentials are read from ~/.config/powermon/powermon.yaml (no separate secret file).