#!/usr/bin/env python3 """Scan an RS485 bus for ZLAC8015D drivers and report which node IDs answer. Requires: pip install pymodbus pyserial Example: python3 zltech_scan_ids.py --port /dev/tty.usbserial-XXXX python3 zltech_scan_ids.py --port COM5 --baud 115200 --range 1 10 """ import argparse import sys from zltech_modbus import REG_NODE_ID, make_client, read_register def scan(port: str, baud: int, id_range, timeout: float): found = [] client = make_client(port, baud, timeout) if not client.connect(): print(f"ERROR: could not open serial port {port}") sys.exit(1) try: for node_id in id_range: values = read_register(client, node_id, REG_NODE_ID, 1) if values is not None: found.append((node_id, values[0])) print(f" id {node_id:3d}: responded (node-id register reads {values[0]})") finally: client.close() return found def main(): parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("--port", required=True, help="Serial port, e.g. /dev/tty.usbserial-XXXX or COM5") parser.add_argument("--baud", type=int, default=115200, help="Baud rate (default 115200, the driver default)") parser.add_argument("--range", nargs=2, type=int, metavar=("START", "END"), default=[1, 16], help="Inclusive node-ID range to scan (default 1 16)") parser.add_argument("--timeout", type=float, default=0.15, help="Per-ID response timeout in seconds") args = parser.parse_args() start, end = args.range id_range = range(start, end + 1) print(f"Scanning {args.port} @ {args.baud}bps for node IDs {start}-{end} ...") found = scan(args.port, args.baud, id_range, args.timeout) print() if found: print(f"Found {len(found)} driver(s):") for node_id, _ in found: print(f" -> ID {node_id}") else: print("No drivers responded. Check wiring, baud rate, and that only powered drivers are on the bus.") sys.exit(1) if __name__ == "__main__": main()