8.1 KiB
2026-04-27 — LVX6048 remote-control plane
Built the bridge from Home Assistant down to the inverter PI18 setters, so
day-to-day knobs (output / charger priorities, charge-current caps) can be
flipped from a dashboard without touching the LCD or a shell. Three
components: powermon's built-in adhoc mechanism enabled, a Python shim that
validates and mirrors commands, and HA-side mqtt: / Lovelace configs.
What happened
-
Surveyed PI18 setters available on this firmware. Confirmed
POP / PCP / PSP / PEI / PDI / MCHGC / MUCHGC / MCHGV / PSDV / BUCD / PBTfrom our patch. Common PI30-only setters (PE/PD,POPM,PF,PCVV,PSAVE, etc.) may also be accepted but weren't tested today. No software AC-output toggle exists on this family — that requires a downstream contactor. -
Phase 1 — enabled powermon's adhoc command queue. Powermon already ships an MQTT-based adhoc mechanism (
adhoc_topic/adhoc_result_topicundermqttbroker). Added both keys topowermon{,2}.yaml:mqttbroker: adhoc_topic: powermon/lvx6048_{1,2}/addcommand adhoc_result_topic: powermon/lvx6048_{1,2}/resultVerified end-to-end with a
PI(protocol ID) query — both units respondedprotocol_id=18within ~1 s. -
Phase 2 — validation shim (
lvx-control). New systemd-managed Python daemon that subscribes tosolar/control/lvx6048/<action>, validates the payload against an allow-list (matching the rulesflash.pyalready enforces), encodes to PI18, and mirrors to both inverters' addcommand topics so the parallel cluster never desyncs on a setting (which would trigger fault 86 — "Parallel output setting different"). Reuses the existing powermon venv's Python at install time (same shebang-rewrite pattern aslvx-resolve-links), so no new dependency setup. Broker creds read from~/.config/powermon/powermon.yaml, so no new secret file to manage. Risky setters (battery thresholds, type, output mode, factory reset) are deliberately not exposed here — those still go throughflash.py apply.Supported actions:
output_priority— POP (SUB / SBU)charger_priority— PCP (solar-first / solar+utility / solar-only)solar_power_priority— PSP (battery-first / load-first)max_charging_current— MCHGC (10–80 A in 10 A steps)max_utility_charging_current— MUCHGC (2 / 10–80 A)
-
Phase 3 — HA-side configs. Mirrors the
eg4battery/homeassistant/pattern.homeassistant/mqtt_controls.yamldefines 4 selects + 1 number bound to the friendly control topics; state is read from the existing PIRI auto-discovery sensors viavalue_templatemappings (PIRI publishes "Solar - Battery - Utility" while the shim accepts "solar_battery_utility").homeassistant/lovelace_controls.yamlis a complete dashboard view: summary header, output/charger control, charge-current control, history graph, per-unit health glance.homeassistant/README.mddocuments the install path and the control- plane architecture. -
MOD decoder regression fix. Powermon services were crash-looping (~3,000 restarts on unit-2) because the inverter started reporting mode
07post-commissioning, which our decoder didn't know — it raisedKeyErrorinstead of falling back. Added"07": "Eco"(best guess; revisit if observed in non-Eco contexts) plus placeholder labels"Mode 08"…"Mode 15"so any future unknown code shows up as an opaque label rather than crashing. Defensive expansion via dict comprehension kept the change small. -
Discovered firmware quirk: MCHGC / MUCHGC lock during active charge. While the inverter is in mode
06("Charge") — i.e. actively bank- charging from solar or grid — the firmware rejectsMCHGC/MUCHGCsetter writes (responds with NAK; result topic shows"Failed").POP/PCP/PSP/PEI/PDIwork in all observed modes. This is defensible firmware behavior (don't change current limits while current is flowing) but not a documented one. Workarounds are listed inlvx-control/README.md: retry while in Standby (mode 01), change via LCD Programs 02/11, or useflash.py apply(which stops powermon for exclusive USB access). -
install.shupdated. Now copieslvx-controlinto/usr/local/bin/with the powermon-venv shebang rewrite, installs the systemd unit, andenable --now's the service once~/.config/powermon/powermon.yamlhas real (non-placeholder) creds. Idempotent on re-run.
Net effect
| Metric | Before | After |
|---|---|---|
| Settings changes from HA | LCD or shell only | solar/control/lvx6048/<action> topic |
| Mirror to both inverters | manual / coordinated | automatic (single publish) |
| Validation before sending | none / firmware regex | shim allow-list + firmware regex |
| Audit trail | none | journalctl -u lvx-control.service |
| MOD-code crash on unknown value | yes (003,054 restarts on unit-2) | no (defensive 08–15 fallback) |
Files touched
M LVX6048/README.md (directory listing + status note)
M LVX6048/config/powermon/powermon.yaml (adhoc topics)
M LVX6048/config/powermon/powermon2.yaml (adhoc topics)
M LVX6048/install.sh (deploys lvx-control)
M LVX6048/powermon-patches/pi18.py (MOD 07 + 08-15 placeholders)
A LVX6048/etc/systemd/system/lvx-control.service (new systemd unit)
A LVX6048/lvx-control/lvx-control (new Python daemon)
A LVX6048/lvx-control/README.md (supported actions / topics)
A LVX6048/homeassistant/mqtt_controls.yaml (HA select + number entities)
A LVX6048/homeassistant/lovelace_controls.yaml (dashboard view)
A LVX6048/homeassistant/README.md (HA-side install steps)
A LVX6048/2026-04-27-control.md (this file)
How to verify
# 1. Services healthy
systemctl --no-pager is-active \
lvx-resolve-links.service \
powermon.service powermon2.service \
lvx-control.service
# 2. Watch result topics
mosquitto_sub -h <broker> -u mqtt -P <pass> -v \
-t 'powermon/lvx6048_1/result' \
-t 'powermon/lvx6048_2/result' &
# 3. Fire a control command (no-op against current state)
mosquitto_pub -h <broker> -u mqtt -P <pass> \
-t 'solar/control/lvx6048/charger_priority' -m 'solar_first'
# Expected: both inverters publish "Succeeded" within ~1s.
# 4. shim audit log
journalctl -u lvx-control.service -f
# Expect lines like:
# OK charger_priority='solar_first' -> PCP0,0 -> mirror to 2 inverter(s)
# REJECT max_charging_current='999' (amps: 10,20,30,40,50,60,70,80)
Loose ends / next pass
- Phase 4 — HA automations (TOU peak-shaving, storm-prep button, cell-imbalance throttle). Deferred until the manual controls have been used for a few days and the actual desired automations are clear.
- MCHGC / MUCHGC reliability. The current "Failed when in mode 06"
behavior is documented but ugly. Possible improvements:
(a) auto-retry the shim once after a 30 s delay; (b) require the inverter
to be in Standby before sending; (c) extend
flash.pyto push these via the apply path (stops powermon, sets, restarts) and expose that as an HA shell-command. Option (c) is the cleanest if frequent changes matter. - Per-component dashboard for LVX6048 stack. Today's
lovelace_controls.yamlis the first one. Worth a follow-up to add an Energy-dashboard wiring guide once both inverterac_output_active_power- battery
pack_powertemplate sensors stabilize.
- battery
- MOD code 07 label. "Eco" is an educated guess; observe over the next few days and relabel if it shows up in unrelated states. Same as the open follow-up for code 06 from yesterday.
- PE / PD setters (buzzer mute, alarm enable/disable, fault recording toggle, etc.) — these are PI30 family and probably accepted by the LVX6048 PI18 firmware. Worth a quick test before adding to the shim's allow-list, since "mute the buzzer" is a useful HA button.