|
|
před 1 měsícem | |
|---|---|---|
| docs | před 1 měsícem | |
| tools | před 1 měsícem | |
| .gitignore | před 1 měsícem | |
| README.md | před 1 měsícem | |
| must_pv1800_monitor.py | před 1 měsícem |
Real-time monitor for the MUST PV1800 (2024) solar inverter/charger via Modbus RTU.
The PV1800 firmware is non-compliant — it ignores the count field and
often dumps a 39-register block in response to any read. This script
handles that by reading the whole block in one go and extracting the
registers we care about, which is the only way to unambiguously identify
which response belongs to which request.
1a86:7523), shows up as
/dev/ttyUSB0 on the remote host.192.168.44.94, user root. The
CH340 is plugged into this host directly.| File | Purpose |
|---|---|
must_pv1800_monitor.py |
The monitor script. Self-contained — embeds the pyserial-based TCP proxy it runs on the remote host, plus the full PV1800 register map. |
docs/register-map.md |
The PV1800 register map, derived from taHC81/MUST-ESPhome/PH1800 PV1800 EP1800 PV3500 EP3500 RS485 Modbus RTU communication Protocol 1.4.15.xlsx. |
docs/quirks.md |
Things I learned the hard way about the PV1800 firmware and the CH340 driver. Read this before debugging "why isn't it working". |
tools/test_proxy.py |
A standalone copy of the TCP<->serial proxy, useful for ad-hoc debugging with nc or socat. |
# Live updates every 3 s (default)
./must_pv1800_monitor.py
# One snapshot, for scripting
./must_pv1800_monitor.py --once
# JSON output, one line per snapshot
./must_pv1800_monitor.py --json
# If you're on the LXC with the USB cable attached directly
./must_pv1800_monitor.py --serial
# If you already have a socat/ser2net bridge running on a remote host
./must_pv1800_monitor.py --tcp --tcp-host 192.168.44.94 --tcp-port 8502
┌─────────────────┐ SSH ┌────────────────────┐ pyserial ┌──────────────┐
│ this script │ ─────────► │ remote host LXC │ ────────────► │ /dev/ttyUSB0 │
│ (your laptop) │ ◄───────── │ 192.168.44.94 │ ◄──────────── │ (CH340) │
└─────────────────┘ └────────────────────┘ └──────┬───────┘
│ RS-485
▼
┌──────────────┐
│ MUST PV1800 │
│ slave ID 4 │
└──────────────┘
/tmp/.must_pv1800_proxy.py)
over SFTP and runs it as a detached background process.docs/quirks.md), then opens /dev/ttyUSB0 and bridges it to
127.0.0.1:9500 on the remote.--interval seconds, and loops.Local: pyserial, paramiko. Install with:
pip install --break-system-packages pyserial paramiko
Remote: python3-serial (apt package). The script auto-installs it if
missing — just needs apt-get available.
Example snapshot (panels disconnected, inverter in ByPass mode feeding a 350W load from grid):
=== 2026-09-10 16:51:55 ===
---------------
CHARGER
---------------
Charger workstate = Standby
MPPT state = Stop
Charging state = Stop
PV voltage = 0.0V
Battery voltage = 27.7V
Charger current = 0.0A
Charger power = 0.0W
---------------
INVERTER
---------------
Inverter Work state = ByPass
Battery voltage = 28.2V
Inverter voltage = 115.7V
Grid voltage = 117.0V
Inverter power = -17W
Grid power = -369W
Load power = 351W
System load = 18.0%
AC radiator temp = 33.0°C
Transformer temp = 52.0°C
Battery power = 13W
Battery current = -3A
PV18-output-example.log shows the
register map in action.PH1800 PV1800 EP1800 PV3500 EP3500 RS485 Modbus RTU communication
Protocol 1.4.15.xlsx (in the same repo) — the authoritative register map
for the inverter family. Parsed copy in docs/register-map.md.[poll error: ...] to stderr.
The next cycle almost always succeeds.Ctrl-C doesn't clean it up, run on the remote:
pkill -9 -f must_pv1800_proxy.