Skip to content

feat(device-discovery): integrate device_discoveryd for device-driven printer config and hotplug - #350

Merged
gmmcosta15 merged 29 commits into
devfrom
feat/device-discovery
Oct 14, 2026
Merged

gmmcosta15 merged 29 commits into
devfrom
feat/device-discovery

Conversation

@HugoCLSC

Copy link
Copy Markdown
Member

Description

  • Feature
  • Bug fix
  • Code refactor
  • Documentation

This branch moves serial device detection from BlocksScreen to the external device_discoveryd daemon, and uses the daemon's device list to keep printer.cfg matched to the hardware that's actually connected.

At boot, BlocksScreen applies the configs for connected devices to printer.cfg and writes the file atomically. If anything changed, it restarts Klipper once Moonraker is up and no print is running. While the screen runs, plugging in a device adds its config, and if the daemon can't be reached, the screen polls /dev/serial/by-id instead. Devices are described by templates in device_profiles.yaml. The AMU is matched by USB ID and only gets [mcu mmu] written after the user confirms, and the beacon's serial path is added automatically.

It also fixes several configuration manager bugs: recursive nested config dirs, the beacon serial path being lost on merge, and the SAVE_CONFIG footer being duplicated on every restart. Files and symlinks are now only rewritten when their content changed.

On the updater side, DeviceDiscovery is now a managed component with its own update hook, and first-time setup runs in install-updater.sh. RF50-Klipper tracks feat/amu-configs for the AMU configs, and BlocksScreen tracks dev. The default log level is now INFO, and the new code paths have unit tests.

Changes

  • Device discovery daemon: BlocksScreen now gets serial devices from the external device_discoveryd daemon instead of scanning them itself. DeviceDiscoveryClient receives its snapshots and hotplug events.
  • Scanner replaced: SerialScanner moved into devices/discovery/serial_devices.py with the same API, and the old tools/serial_scanner.py is gone.
  • Device templates: new templates in device_profiles.yaml say which printer.cfg section to write for each detected device, matched by USB ID or name.
  • Boot sync: at startup, the configs for connected devices are applied to printer.cfg and the file is written atomically. If it changed, Klipper restarts once Moonraker is up and no print is running.
  • Hotplug: a device plugged in while the screen runs gets its config added automatically. If the daemon is down, it falls back to polling /dev/serial/by-id.
  • AMU:
    • Matched on USB ID 0x1d50:0xb001.
    • The screen asks Configure / Not now before it writes [mcu mmu].
    • The answer is saved, so the user isn't asked every time.
  • Beacon: its serial path is added to the config automatically.
  • Configurator fixes:
    • No more recursive nested config dirs.
    • The beacon serial path is kept when configs are merged.
    • The SAVE_CONFIG footer is no longer duplicated on every restart.
    • Files and symlinks are only rewritten when their content changed.
  • Updater:
    • New DeviceDiscovery component and update hook.
    • First-time setup of the daemon runs in install-updater.sh.
    • Services that aren't installed yet are skipped instead of failing.
  • Branch pins: RF50-Klipper tracks feat/amu-configs, and BlocksScreen will track dev once you push the components.yaml change.
  • Logging: the default log level is now INFO instead of DEBUG.
  • Tests: new unit tests for the discovery client, serial devices, the hotplug watcher, an AMU end-to-end flow, the configurator, the device templates, the updater and the main window prompt.

HugoCLSC and others added 28 commits June 22, 2026 16:18
When updating the system for the first time, the configurator
will sync the config repo with the printer config directory,
but it will create rescursive nested config dirs,
the problem has two parts, first, the rescursiveness only happens
when there is an update, and the repo/printer config are out of
sync, the second is because of the legacy configurations.
We now clean the previous printer config repo dirs, before
actually symlinking the repo with the printer configurations. This
is only part of the fix.
The second part of this commit, adds the second sync mode to the
tool, but it will not be used right now, this is prepign for
future work.
Co-authored-by: Guilherme Costa <guilherme.costa@blockstec.com>
Signed-off-by: Hugo Costa <hugo.santos.costa@gmail.com>
There was a problem with printer.cfg merging, everytime merging occured two
things happened, first was that the beacon section on pritner.cfg was not
ignored, this made the configured serial path to be lost, the second problem
was that the saved configuration (footer) was duplicated everytime, so if the
screen restarted we whould have thounsands of lines duplicated.

With this fix, both issues are resolved.

Another quality of life is that, the deletetion of the printer configurations
subdirectories is not done unless there is actually something different between
the config repo and the printers config dir.
…marker

There were a bunch of problems that would make merging files difficult, one
of those was the merger or configparser sections, the default is to use =
but the code was using : to set values to options.
Then there was a problem when checking nestes config dirs on the default
configuration directory. This looks like it has been solved as well.
Fix fallout from the merge:
- Remove a leftover conflict marker in tests/updater/test_executor_unit.py.
- Store the updater's last-seen HEAD as a dict state entry ("_updater"):
  Release-2.0's self-heal reconcile drops non-dict entries, which made every
  boot look like a fresh self-update, and NRestarts priming called .get on it.
- Skip enable_service when a provisioned unit is not installed yet
  (install-updater.sh enables it).
- Stub DeviceConfigManager/DeviceConfigWatcher in test_sigterm_shutdown.py.
- DeviceDiscovery hook comment: HOOK_TIMEOUT is now 600 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
device_discoveryd now reports USB vendor/product IDs for serial devices
(DeviceDiscovery "Report USB vendor/product IDs for serial devices"), so
the AMU profile matches on 0x1d50:0xb001 and a reported ID is final: an
AMU on Klipper's stock ID is no longer recognised by its "AMU" name.
USB_IDS.md and the profile comments described the old fallback.

Watcher tests used a fake manager that matched on the name, so the ID
path was never exercised: add tests that run the daemon's actual AMU
entries through the real profiles.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- AMU profile writes [mcu mmu] (the MCU Happy Hare's mmu.cfg uses) and
  asks the user first (confirm: true); consent persists in
  ~/.config/blockscreen/device_consent.json
- USB vendor/product IDs are read from sysfs, since device_discoveryd
  reports 0 for serial entries
- Boot scan merges the daemon snapshot with /dev/serial/by-id; printer.cfg
  writes are atomic; boot-time changes trigger a Klipper restart
- Watcher polls /dev/serial/by-id when the daemon is unreachable
- MainWindow shows a Configure / Not now prompt and restarts Klipper via
  machine.services.restart once no job is running
- Discovery client resolves the socket path on every connection attempt
- INFO logs along the whole hotplug path

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dedupe sync and client framing, fix SAVE_CONFIG key indent
@HugoCLSC HugoCLSC added enhancement New feature or improvement updater Field updates and self-heal labels Oct 14, 2026
@HugoCLSC
HugoCLSC requested a review from RobeMartins October 14, 2026 15:06
@HugoCLSC HugoCLSC changed the title Feat(device-discovery): integrate device_discoveryd for device-driven printer config and hotplug feat(device-discovery): integrate device_discoveryd for device-driven printer config and hotplug Oct 14, 2026
@gmmcosta15
gmmcosta15 merged commit 9743a24 into dev Oct 14, 2026
9 checks passed
@gmmcosta15
gmmcosta15 deleted the feat/device-discovery branch October 14, 2026 16:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or improvement updater Field updates and self-heal

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants