port_scanner.py 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. # port_scanner.py
  2. import serial.tools.list_ports
  3. def scan_ports() -> list[dict]:
  4. """Returns list of candidate KKL ports."""
  5. ports = serial.tools.list_ports.comports()
  6. candidates = []
  7. for port in ports:
  8. # Prioritize FTDI and common USB-to-Serial
  9. is_likely = False
  10. desc = port.description.lower()
  11. hwid = port.hwid.lower()
  12. if "ftdi" in desc or "ftdi" in hwid or "0403" in hwid:
  13. is_likely = True
  14. elif "usb" in desc or "ch340" in desc or "serial" in desc:
  15. is_likely = True
  16. candidates.append({
  17. "device": port.device,
  18. "description": port.description,
  19. "is_likely": is_likely
  20. })
  21. # Sort likely ports first
  22. candidates.sort(key=lambda x: not x["is_likely"])
  23. return candidates
  24. def auto_select() -> str | None:
  25. """Returns the best-guess port, or None if ambiguous or none found."""
  26. ports = scan_ports()
  27. if not ports:
  28. return None
  29. likely_ports = [p for p in ports if p["is_likely"]]
  30. if len(likely_ports) == 1:
  31. return likely_ports[0]["device"]
  32. elif len(likely_ports) > 1:
  33. # If multiple likely, return None to force user choice
  34. return None
  35. elif len(ports) > 0:
  36. # Fallback to first available if no obvious candidate
  37. return ports[0]["device"]
  38. return None