#!/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()
