Files
shaggy-solar/battery/probe.py
2026-04-24 16:34:10 -04:00

65 lines
2.3 KiB
Python

#!/usr/bin/env python3
"""Sanity-check byte-level probe for EG4 LifePower4 V2 over USB-RS485.
Sends the 'general status' frame and prints the raw reply. If you see bytes
starting with 0x7E coming back, the protocol is confirmed and eg4_lifepower.py
will decode them.
Usage:
python3 probe.py # auto-detect likely USB-serial port
python3 probe.py /dev/tty.usbserial-XXX # explicit port
python3 probe.py COM5 # Windows
"""
import sys
import time
import glob
import serial # pip install pyserial
BAUD = 9600
CMDS = {
"general": bytes.fromhex("7E01010000FE0D"[:-2] + "0D"), # 7E 01 01 00 FE 0D
"hw_ver": bytes.fromhex("7E01420000FC0D"[:-2] + "0D"), # 7E 01 42 00 FC 0D
"fw_ver": bytes.fromhex("7E01330000FE0D"[:-2] + "0D"), # 7E 01 33 00 FE 0D
}
# (the [:-2]+"0D" dance above is just to keep the literal aligned with the
# canonical 6-byte frames documented upstream; simpler form below)
CMDS = {
"general": bytes([0x7E, 0x01, 0x01, 0x00, 0xFE, 0x0D]),
"hw_ver": bytes([0x7E, 0x01, 0x42, 0x00, 0xFC, 0x0D]),
"fw_ver": bytes([0x7E, 0x01, 0x33, 0x00, 0xFE, 0x0D]),
}
def autodetect() -> str | None:
candidates = (
glob.glob("/dev/tty.usbserial*") # macOS FTDI/CH340
+ glob.glob("/dev/tty.usbmodem*") # macOS CDC-ACM
+ glob.glob("/dev/ttyUSB*") # Linux FTDI/CH340
+ glob.glob("/dev/ttyACM*") # Linux CDC-ACM
)
return candidates[0] if candidates else None
def probe(port: str) -> None:
print(f"opening {port} @ {BAUD} 8N1")
with serial.Serial(port, BAUD, bytesize=8, parity="N", stopbits=1, timeout=1.5) as s:
for name, cmd in CMDS.items():
s.reset_input_buffer()
s.write(cmd)
time.sleep(0.2)
reply = s.read(256)
print(f"\n[{name}] sent {cmd.hex(' ')}")
if reply:
print(f" got ({len(reply)} bytes) {reply.hex(' ')}")
if reply[0] == 0x7E and reply[-1] == 0x0D:
print(" -> frame looks valid (7E ... 0D)")
else:
print(" got (nothing — timeout)")
if __name__ == "__main__":
port = sys.argv[1] if len(sys.argv) > 1 else autodetect()
if not port:
sys.exit("no serial port found; pass one explicitly: python3 probe.py /dev/tty.usbserial-XXXX")
probe(port)