Files
shaggy-solar/eg4battery/Install.md
2026-04-25 19:00:44 -04:00

160 lines
5.4 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.
# EG4 LifePower4 v2 → HA Monitoring Install
Target: Debian-family Linux (developed on Raspberry Pi CM5), one USB-to-RS-485
adapter per pack's **RS485** socket, HA MQTT broker on the LAN.
> **Shortcut:** [`install.sh`](./install.sh) automates §3§7 and supports
> `--dry-run` for a no-hardware smoke test. This doc explains what it does
> and how to do it by hand.
Path conventions: `$BASE` = root of this package (e.g. `~/solar/eg4battery`).
## 1. Prerequisites
- `uv` on `$PATH` ([docs](https://docs.astral.sh/uv/))
- `sudo`
- **One USB-to-RS-485 adapter per pack**. FTDI-based is what we've tested
(FT232R + MAX485 combo, identified by the Linux kernel as `FT232R USB UART`
with a unique serial-number suffix). CH340 / CP210x also fine — adjust
the udev rule's vendor/product ID.
## 2. Cabling — read this before wiring
LP4V2 back panel has four RJ45 sockets: `CAN`, `RS485`, `Comm1`, `Comm2`.
Only `RS485` is relevant for our daemon:
| Socket | Use for monitoring? |
|--------|---------------------------------------------------------------------|
| CAN | No — separate bus, CAN signaling, for inverter BMS comms |
| RS485 | **Yes.** External monitor port. Pin 1-2 = B/A. Modbus RTU at 9600. |
| Comm1 | No — inter-pack hub bus (19200 Modbus). Leave for pack daisy-chain. |
| Comm2 | No — same internal bus as Comm1. |
The stock EG4 USB-RS-485 cable (included with each pack) is already wired
correctly for the RS485 socket (pins 1-2 / A-B).
**Topology**: each pack gets its own adapter plugged into its **RS485** socket.
No daisy chain required for monitoring — each pack is a dedicated bus. The
Comm1↔Comm2 daisy chain between packs is separate and carries the inter-pack
hub bus (not our concern).
## 3. udev rule
Grants `dialout` group access to FTDI USB-serial adapters.
```bash
sudo install -m 644 "$BASE/etc/udev/rules.d/99-eg4-rs485.rules" \
/etc/udev/rules.d/99-eg4-rs485.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=tty
ls -l /dev/serial/by-id/ # expect one symlink per adapter
```
## 4. Daemon binary
```bash
sudo install -m 755 "$BASE/bin/eg4-battery" /usr/local/bin/eg4-battery
```
uv handles deps; no venv work on your side.
## 5. Config
Canonical template: [`config/eg4-battery.yaml.example`](./config/eg4-battery.yaml.example).
```bash
mkdir -p ~/.config/eg4-battery
install -m 600 "$BASE/config/eg4-battery.yaml.example" \
~/.config/eg4-battery/eg4-battery.yaml
# Edit — see "mode selection" below
```
### 5a. mode selection
- **`modbus_per_pack`** (default / recommended). Each pack listed with its own
`port:`, `address:` and `baud:` — the daemon opens one serial port per pack
and polls each independently. **Two Modbus reads per cycle per pack**:
block 1 (39 regs at 0x0000, live status) + block 2 (91 regs at 0x002D,
counters + model + firmware strings). ~150 ms per pack at 9600 baud.
```yaml
bus:
mode: modbus_per_pack
timeout_s: 1.0
poll_interval_s: 10.0
packs:
- name: lifepower4_1
address: 0x40
port: /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_<ID1>-if00-port0
baud: 9600
- name: lifepower4_2
address: 0x40
port: /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_<ID2>-if00-port0
baud: 9600
```
- **`active`** (legacy, V1 hardware only) — single shared bus, EG4 7E/0D
protocol at 9600. Not used on V2 Auto-Addressing hardware.
- **`passive`** (diagnostic) — listen-only Modbus sniff at 19200. See
[`NOTES.md`](./NOTES.md) "Modes" for details.
### 5b. MQTT creds
Replace `<MQTT_BROKER_IP>`, `<MQTT_USER>`, `<MQTT_PASSWORD>`. `install.sh`
will not auto-start the service while those placeholders remain.
## 6. Smoke test without hardware
```bash
eg4-battery -C ~/.config/eg4-battery/eg4-battery.yaml --dry-run
```
Mock transport, one cycle per pack, prints every discovery-config and
state-topic / payload to stdout. Confirms the pipeline end-to-end before
hardware is involved.
## 7. systemd
```bash
sudo install -m 644 "$BASE/etc/systemd/system/eg4-battery.service" \
/etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now eg4-battery.service
journalctl -u eg4-battery.service -f
```
Service includes `Environment=PATH=…` so uv is found under systemd.
## 8. Bring up additional packs
When a new pack comes online:
1. Plug its adapter into the pack's **RS485** socket and power the pack.
2. `ls -l /dev/serial/by-id/` — note the new symlink.
3. Add / update an entry in `~/.config/eg4-battery/eg4-battery.yaml`:
```yaml
- name: lifepower4_N
address: 0x40
port: /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_<ID>-if00-port0
baud: 9600
```
4. `sudo systemctl restart eg4-battery.service`. The journal shows
`pack lifepower4_N: recovered after N failed cycle(s)` within ~10 s when
the pack starts responding, and HA auto-discovers ~65 entities.
## 9. Verify MQTT flow
```bash
# modbus_per_pack: all named + raw register entities per pack
mosquitto_sub -h <broker> -u mqtt -P <pass> \
-t 'homeassistant/sensor/lifepower4_+_pack_voltage/state' \
-t 'homeassistant/sensor/lifepower4_+_soc/state' \
-t 'homeassistant/sensor/lifepower4_+_cell_voltage_delta_mv/state' \
-v
```
## 10. Swapping modes later
Change `bus.mode` in the config, restart the service. Config reshape varies
per mode — see §5a. No binary redeploy needed.