- 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>
5.1 KiB
EG4 LifePower4 v2 → Home Assistant
Daemon that polls EG4 LifePower4 48V 100Ah v2 (Auto-Addressing) packs over RS-485 and publishes per-pack telemetry to MQTT with HA auto-discovery.
Status: live
All 6 packs publishing in modbus_per_pack mode, each on its own FTDI
RS-485 adapter (packs 1–5 at addr 0x40/9600; pack 6 is an oddball at addr
0x01/115200). Per pack, ~70 named entities + 136 raw register_NN series:
lifepower4_1_pack_voltage 52.56 V (16 cells × 3.285 V)
lifepower4_1_cell_01_voltage 3.285 V
lifepower4_1_cell_voltage_delta_mv 2 (outstanding balance)
lifepower4_1_soc 100 %
lifepower4_1_capacity_ah 100.0 Ah
lifepower4_1_temperature_pcb 55 °C
lifepower4_1_model "LFP-51.2V100Ah-V1.0"
lifepower4_1_firmware_version "Z03T21"
lifepower4_1_firmware_date "20260206"
... plus 14 warning bits, 14 protection bits, all 136 raw registers
The decoder maps registers to fields per a layout reverse-engineered from
the EG4 BMS Tool's Mach-O binary (see NOTES.md §"Modbus
polling" and §"Register map"). Each cycle, the daemon issues two Modbus
fn=0x03 reads per pack — block 1 (39 regs at 0x0000) for live status, and
block 2 (91 regs at 0x002D) for counters + model + firmware strings —
mirroring what the vendor BMS Tool itself does.
Modes
Set by bus.mode in ~/.config/eg4-battery/eg4-battery.yaml:
| Mode | When to use |
|---|---|
modbus_per_pack |
Default. One FTDI per pack's RS485 port. Fully decoded HA entities. |
active |
Legacy 7E/0D (V1 firmware only). Not used on V2 hardware. |
passive |
Listen-only Modbus sniff (19200). Diagnostic use. |
See NOTES.md for architecture, register map, LVX6048
compatibility findings, and bring-up checklist.
SoC drift & calibration
The per-pack BMS SoC is coulomb-counted and drifts because the conservative
LVX6048 charge profile rarely drives a true full charge, so the counters never
re-anchor to 100% (observed 8–70% spread across packs at an identical resting
voltage — they're all physically at the same charge; the spread is pure drift).
Fix is a periodic full charge to absorption, which re-anchors every pack to
100%. Automated by the calibration-charge skill (solar-only, or grid-assisted
via output-priority SUB on a cloudy day) — see
../.claude/skills/calibration-charge/
and ../.claude/skills/lib/grid-cal-monitor.
What's in the box
eg4battery/
├── README.md ← start here
├── Install.md ← detailed walkthrough + mode-switch howto
├── NOTES.md ← architecture, register map, port matrix
├── install.sh ← idempotent installer (supports --dry-run)
│
├── bin/eg4-battery ← single-file daemon (uv PEP-723 inline deps)
│
├── config/eg4-battery.yaml.example ← template, multiple-pack config
│
├── etc/ mirror of target paths (Pi side)
│ ├── udev/rules.d/99-eg4-rs485.rules
│ └── systemd/system/eg4-battery.service
│
├── homeassistant/ ← drop into your HA config dir
│ ├── README.md (what goes where + retention tiers)
│ ├── recorder.yaml (exclude noisy / diagnostic entities)
│ ├── template_sensors.yaml (derived: power, temp_max, cell_imbalance, stack rollups)
│ └── lovelace_overview.yaml (3-pack stack dashboard)
│
└── tmp/ ad-hoc diagnostics
├── port-probe (single-cycle 9600/19200/7E probe)
├── eg4-snapshot (47-reg dump for BMS Tool cross-check)
└── bms-tool-ref/ (unpacked vendor BMS Tool for RE reference)
Quick start on a fresh host
cd ~/solar/eg4battery
./install.sh --dry-run # mock cycle, prints MQTT payloads, exits
# Edit ~/.config/eg4-battery/eg4-battery.yaml:
# - For modbus_per_pack: one 'packs:' entry per pack, each with port + address + baud
# - mqtt.host / username / password
./install.sh # real deploy; auto-starts once creds are filled
journalctl -u eg4-battery.service -f
Related packages
../LVX6048/— inverter-side monitoring via PI18 over USB-HID. Same MQTT broker. Between the two packages, HA sees every useful number from the stack.
Acknowledgements
battery/eg4_lifepower.py— V1 protocol decoder adapted fromLouisvdw/dbus-serialbattery. Historical; V2 firmware moved to Modbus on a different port.- EG4 Electronics
lv_host.app— the vendor BMS Tool; its Qt binary's SQLite schema and strings gave us the register-to-field mapping.