Skip to content

Discover devices automatically in the machine wizard - #376

Merged
knipknap merged 1 commit into
usb-first-port-selectorfrom
auto-device-discovery
Aug 25, 2026
Merged

knipknap merged 1 commit into
usb-first-port-selectorfrom
auto-device-discovery

Conversation

@knipknap

Copy link
Copy Markdown
Contributor

Stacked on #371.

Summary

Adds a discovery-first flow to the machine configuration wizard. Plugging in a machine and opening "Add Machine" is now enough to get a fully configured device — no forms, no baud-rate guessing.

Architecture

Discovery is split into two processes (scan once, evaluate many):

  • Scanning (machine/transport/serial_scan.py, transport layer): opens every serial port once per scan, probes it across the candidate baud rates, and captures everything the device sends — unsolicited banner first, then responses to \n / ? nudges, plus a quiet-gap drain for multi-line bursts. Firmware-agnostic; a generic mostly-printable-output heuristic decides when a port is talking.
  • Evaluating (machine/driver/discovery.py): drivers declare a DISCOVERY = DeviceRecognizer(label, matches, name, firmware) class attribute — pure data, no behavior. find_all_devices() runs one scan and lets every recognizer evaluate the captured bytes. Adding serial drivers costs zero additional port opens.

Wizard flow

  1. Discover page: scans while visible, lists found devices with an explicit Select button, and probes each found device automatically ($I/$$) — no interaction. Rows update live to show what the machine reported about itself (e.g. "Sculpfun iCube, 120×120 mm work area").
  2. On selection, all collected identity data (USB descriptors, firmware banner, probed machine name) feeds profile matching against vendor/model tokens declared in every built-in device.yaml.
  3. Unique match → the curated profile is adopted (live connection facts preserved), and every step whose data is already known is skipped — straight to Review in the common case.
  4. No match → the profile picker comes up pre-filtered to matching vendors/controllers, with probe specs already merged into the working machine.

Notable details

  • Grbl forks that greet with $I-style build info instead of a boot banner (e.g. Sculpfun iCube) are recognized via [VER:/[OPT:/[MSG: markers; [MSG:machine:...]/mechine: names drive both the row title and profile matching.
  • A bare ok ack never claims a port by itself (Marlin acks identically) — nudge responses are accumulated so recognition has full context.
  • Ports of already-found devices are excluded from rescans (avoids DTR-resetting identified machines and probe races); unplugged ports are pruned via port enumeration.
  • Fixes a crash in the laser control widget when deleting the active machine (ValueError: No machine found with ID … from lazy controller resolution during signal disconnect).

Test plan

  • New: tests/machine/transport/test_serial_scan.py (single-open semantics, baud ordering, garbage fall-through, exclusion, lock serialization), tests/machine/driver/test_discovery.py (one-scan-serves-all-drivers, bannerless GRBL, real Sculpfun banner end-to-end), tests/machine/device/test_profile_matching.py.
  • Wizard UI tests extended: auto-probe enrichment, step-skipping routes for matched/unmatched flows, vendor-filtered picker, Select button.
  • Full suite: 2199+ backend tests and 58 wizard tests green; verified against real hardware (Sculpfun iCube over USB serial).

Add a discovery-first flow to the machine configuration wizard:

- Transport layer gains a generic serial scanner that opens each
  port once, probes it across baud rates, and captures whatever the
  device sends (banner plus nudged responses).
- Drivers declare a DISCOVERY recognizer (label, firmware matcher,
  device-name extractor) instead of running scans themselves;
  adding drivers never multiplies scan cost.
- The new first wizard step lists found devices and probes them
  without interaction; rows then show the machine's own name and
  work area.
- All collected identity data feeds profile matching against
  vendor/model tokens declared in every built-in device.yaml; on a
  unique match the curated profile is adopted and every step whose
  data is already known is skipped.
- When no profile matches, the profile picker is pre-filtered to
  matching vendors and controllers.
- Fix crash in the laser control widget when the active machine is
  deleted while its signals are still attached.
@knipknap
knipknap merged commit 06d1df3 into usb-first-port-selector Aug 25, 2026
28 checks passed
@knipknap
knipknap deleted the auto-device-discovery branch August 25, 2026 18:01

This branch was previously deployed

1 inactive deployment
pypi — 7dd26151 Deployed Aug 24, 2026 by knipknap via Build and Publish Wheel #1765
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant