Files
shaggy-solar/eg4battery/tmp/port-probe
2026-04-24 16:34:10 -04:00

65 lines
2.2 KiB
Python
Executable File

#!/home/noise/.local/share/uv/tools/powermon/bin/python
"""One-shot diagnostic: autodetect the currently-plugged FTDI, then
run 3 tests and print results.
1. Passive listen 10 s @ 9600 baud.
2. Passive listen 10 s @ 19200 baud.
3. Active probe: send canonical 7E 01 01 00 FE 0D at 9600, wait 2 s.
Usage: port-probe <label>
"""
import glob, sys, time, serial
def autodetect():
hits = sorted(glob.glob("/dev/serial/by-id/usb-FTDI_*"))
return hits[0] if hits else None
def passive(port, baud, seconds):
with serial.Serial(port, baud, bytesize=8, parity="N", stopbits=1, timeout=0.25) as p:
p.reset_input_buffer()
deadline = time.monotonic() + seconds
buf = bytearray()
while time.monotonic() < deadline:
chunk = p.read(512)
if chunk: buf.extend(chunk)
return bytes(buf)
def probe(port, baud):
frame = bytes([0x7E, 0x01, 0x01, 0x00, 0xFE, 0x0D])
with serial.Serial(port, baud, bytesize=8, parity="N", stopbits=1, timeout=0.25) as p:
p.reset_input_buffer()
p.write(frame)
deadline = time.monotonic() + 2.0
buf = bytearray()
while time.monotonic() < deadline:
chunk = p.read(512)
if chunk: buf.extend(chunk)
return bytes(buf)
def modbus_q_count(buf):
return sum(1 for i in range(len(buf) - 7)
if buf[i+1] == 0x03 and buf[i+2] == 0 and buf[i+3] == 0 and buf[i+5] == 0x2f)
def main():
label = sys.argv[1] if len(sys.argv) > 1 else "test"
port = autodetect()
if port is None:
print("ERROR: no FTDI adapter visible at /dev/serial/by-id/usb-FTDI_*")
sys.exit(2)
print(f"=== {label} ===")
print(f"adapter: {port}")
for baud in (9600, 19200):
buf = passive(port, baud, 10)
print(f"\npassive @ {baud:>5}: {len(buf):4d} bytes ({len(buf)/10:4.1f} B/s)"
f" 7E={buf.count(0x7E)} 0D={buf.count(0x0D)}"
+ (f" mb_queries≈{modbus_q_count(buf)}" if baud == 19200 else ""))
if buf:
print(f" first 80: {bytes(buf[:80]).hex(' ')}")
buf = probe(port, 9600)
print(f"\n7E probe @ 9600: reply {len(buf)} bytes")
if buf:
print(f" hex: {bytes(buf).hex(' ')}")
if __name__ == "__main__":
main()