# 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_priority` → `solar_utility_battery` (SUB) so the inverter runs loads off grid and charges the battery to full, plus `charger_priority` → `solar_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 ```bash # subscribe to results in another terminal mosquitto_sub -h -u mqtt -P -v \ -t 'powermon/lvx6048_1/result' \ -t 'powermon/lvx6048_2/result' # fire a control command mosquitto_pub -h -u mqtt -P \ -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).