Add interactive target and port selection to sync.py and port listing to detect_boards.py#333
Add interactive target and port selection to sync.py and port listing to detect_boards.py#333
Conversation
…sync.py - detect_boards.py: when run as `./dev/detect_boards.py list`, calls list_pico_ports() and prints each port on its own line. Default behavior (no args) is preserved. - sync.py: when a target system is specified but no port is given (and not 'auto'), detects connected ports and lets the user interactively select one. Auto-selects if only one port is found. Agent-Logs-Url: https://github.com/warped-pinball/vector/sessions/70888ab8-6f09-44ed-97c2-723f949eb5c0 Co-authored-by: mullinmax <14000345+mullinmax@users.noreply.github.com>
|
Developer build links: Sys11 (Tiny) WPC EM WhiteStar DataEast |
There was a problem hiding this comment.
Pull request overview
This PR improves the developer flashing workflow by adding a simple “list ports” mode to detect_boards.py and introducing interactive serial-port selection in sync.py when no port is provided, reducing the need to manually discover /dev/tty* names.
Changes:
- Add
dev/detect_boards.py listto print detected Pico serial ports (one per line). - Update
dev/sync.pyto auto-select the only detected port or prompt the user to choose among multiple detected ports whenportis omitted.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
dev/sync.py |
Adds port autodetection + interactive selection when no port argument is provided. |
dev/detect_boards.py |
Adds a list CLI mode to print ports returned by list_pico_ports(). |
| if not ports: | ||
| print("No boards detected.") | ||
| return 1 | ||
| if len(ports) == 1: | ||
| port = ports[0] | ||
| print(f"Using detected port: {port}") | ||
| else: |
There was a problem hiding this comment.
When port is omitted, this now hard-depends on list_pico_ports()/mpremote devs and aborts with "No boards detected." if it returns an empty list. That’s a behavioral change from the previous flow (which let dev/flash.py run its own autodetect via mpremote connect list) and can become a false-negative on environments where mpremote devs isn’t supported or fails transiently. Consider only prompting when list_pico_ports() returns >1, and otherwise fall back to passing port=None through to flash_single() so flash.py’s autodetect/error messaging remains the source of truth.
| if not ports: | |
| print("No boards detected.") | |
| return 1 | |
| if len(ports) == 1: | |
| port = ports[0] | |
| print(f"Using detected port: {port}") | |
| else: | |
| if len(ports) == 1: | |
| port = ports[0] | |
| print(f"Using detected port: {port}") | |
| elif len(ports) > 1: |
| rc = flash_single(args.system, args.port, args.write_config) | ||
| port = args.port | ||
| if port is None: | ||
| ports = list_pico_ports() |
There was a problem hiding this comment.
list_pico_ports() uses subprocess.run(["mpremote", ...]) and doesn’t catch FileNotFoundError/OSError when mpremote isn’t installed or isn’t on PATH. With this new code path, that can surface as an unhandled traceback instead of a clean CLI error. Wrap the list_pico_ports() call in a try/except (or update list_pico_ports() to handle OSError) and print a clear message + non-zero exit.
| ports = list_pico_ports() | |
| try: | |
| ports = list_pico_ports() | |
| except OSError as exc: | |
| print(f"Unable to detect Pico ports. Ensure mpremote is installed and available on PATH. ({exc})") | |
| return 1 |
|
@copilot if the user doesn't specify a target hardware (and does not use "auto") also list the target hardware options and allow the user to interactively select them the way we do for ports. Make the interactive menu functionality into a reuseable function that's minimal. |
- Extract interactive_select(label, options) as a reusable menu function - Add list_hardware_targets() to discover targets from src/ directory - When no system arg is given, prompt user to select a hardware target - When no port arg is given, prompt user to select from detected ports (falls through to flash.py autodetect if no ports found) - Handle OSError in list_pico_ports() for missing mpremote Agent-Logs-Url: https://github.com/warped-pinball/vector/sessions/2c1e83f8-c05f-4331-9376-3901ba80bd53 Co-authored-by: mullinmax <14000345+mullinmax@users.noreply.github.com>
Done in 321cf6a. When no system is specified, Both menus use a shared Example flow with no args: |
Description
Quality-of-life improvements for the dev workflow, similar in spirit to #278:
detect_boards.py list— runslist_pico_ports()and prints one port per line. Default behavior (no args) unchanged.sync.py— when no system argument is provided (e.g. justpython dev/sync.py), discovers available hardware targets fromsrc/and prompts the user to select one interactively.sync.py— when no port is specified, lists detected Pico ports and prompts for selection. Auto-selects if only one port is connected. Falls through toflash.pyautodetect if no ports are found.interactive_select(label, options)— minimal shared function used by both target and port selection. Auto-selects single options, handles cancel/invalid input gracefully.OSErrorhandling —list_pico_ports()now catchesOSError(e.g.mpremotenot installed) and returns an empty list instead of raising an unhandled traceback.Related Issues
Motivation and Context
Specifying a port manually is faster than
auto(which queries board type for every port), but requires knowing the port name. Running with no args previously defaulted todevwhich isn't a valid hardware target. Now, runningsync.pywith no arguments gives a fully guided interactive experience — pick your target, pick your port, and go.Testing
detect_boards.pydefault (no-arg) behavior preservedlistsubcommand prints portssync.pyinteractive target selection: discovers targets fromsrc/, handles single target (auto-select), multiple targets (prompt), no targets (error)sync.pyinteractive port selection: single port (auto-select), multiple ports (prompt), no ports (falls through to flash.py autodetect)python dev/sync.py sys11 /dev/ttyACM0)Screenshots (if applicable)
Types of Changes
Checklist
Additional Notes
Backward-compatible: all existing imports from
detect_boardsand explicitsync.pyargument patterns (e.g.sync.py sys11 /dev/ttyACM0,sync.py auto) continue to work identically. The only behavioral change is that runningsync.pywith no arguments now prompts interactively instead of defaulting to thedevtarget.