- 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>
105 lines
4.8 KiB
Markdown
105 lines
4.8 KiB
Markdown
# 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 <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).
|