Files
shaggy-solar/LVX6048/2026-04-27-control.md
2026-04-27 06:50:04 -04:00

165 lines
8.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
1. **Surveyed PI18 setters available on this firmware.** Confirmed
`POP / PCP / PSP / PEI / PDI / MCHGC / MUCHGC / MCHGV / PSDV / BUCD / PBT`
from 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.
2. **Phase 1 — enabled powermon's adhoc command queue.** Powermon already
ships an MQTT-based adhoc mechanism (`adhoc_topic` / `adhoc_result_topic`
under `mqttbroker`). Added both keys to `powermon{,2}.yaml`:
```yaml
mqttbroker:
adhoc_topic: powermon/lvx6048_{1,2}/addcommand
adhoc_result_topic: powermon/lvx6048_{1,2}/result
```
Verified end-to-end with a `PI` (protocol ID) query — both units
responded `protocol_id=18` within ~1 s.
3. **Phase 2 — validation shim (`lvx-control`).** New systemd-managed
Python daemon that subscribes to `solar/control/lvx6048/<action>`,
validates the payload against an allow-list (matching the rules
`flash.py` already 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 as `lvx-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 through `flash.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 (1080 A in 10 A steps)
- `max_utility_charging_current` — MUCHGC (2 / 1080 A)
4. **Phase 3 — HA-side configs.** Mirrors the `eg4battery/homeassistant/`
pattern. `homeassistant/mqtt_controls.yaml` defines 4 selects + 1
number bound to the friendly control topics; state is read from the
existing PIRI auto-discovery sensors via `value_template` mappings
(PIRI publishes "Solar - Battery - Utility" while the shim accepts
"solar_battery_utility"). `homeassistant/lovelace_controls.yaml` is
a complete dashboard view: summary header, output/charger control,
charge-current control, history graph, per-unit health glance.
`homeassistant/README.md` documents the install path and the control-
plane architecture.
5. **MOD decoder regression fix.** Powermon services were crash-looping
(~3,000 restarts on unit-2) because the inverter started reporting
mode `07` post-commissioning, which our decoder didn't know — it
raised `KeyError` instead 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.
6. **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 rejects `MCHGC` / `MUCHGC`
setter writes (responds with NAK; result topic shows `"Failed"`).
`POP` / `PCP` / `PSP` / `PEI` / `PDI` work 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 in `lvx-control/README.md`: retry while in Standby (mode 01),
change via LCD Programs 02/11, or use `flash.py apply` (which stops
powermon for exclusive USB access).
7. **`install.sh` updated.** Now copies `lvx-control` into
`/usr/local/bin/` with the powermon-venv shebang rewrite, installs
the systemd unit, and `enable --now`'s the service once
`~/.config/powermon/powermon.yaml` has 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 0815 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
```bash
# 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.
```
```bash
# 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.py` to 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.yaml` is the first one. Worth a follow-up to add an
Energy-dashboard wiring guide once both inverter `ac_output_active_power`
+ battery `pack_power` template sensors stabilize.
- **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.