Release v1.7.5 — Snapmaker U1 direct-mode integration#183
Conversation
Phase 1 of Snapmaker U1 direct-mode support. The scanner pushes scan results straight to the U1's external filament-detection endpoint exposed by paxx12's Extended Firmware. No middleware, no Klipper macros — a single HTTP POST per generic-UID scan. Scope (one scanner per toolhead, fixed-channel): - New web config section "Snapmaker U1 Integration" with Enable toggle + channel picker (0-3) and a hint link to the Extended Firmware repo. - New NVS keys u1_on / u1_channel; loaded with bounds clamp on read. - publishToU1() builds the U1 info schema (VENDOR / MAIN_TYPE / SUB_TYPE / RGB_1 / ALPHA / HOTEND_*_TEMP / BED_TEMP / CARD_UID), splits material names like "PLA Matte" on first space, parses #RRGGBB into the firmware's RGB_1 integer, and emits the spool UID as a byte array. - 30s reachability backoff after a transport failure plus 250ms mutex wait with skip-if-busy so an offline U1 doesn't block the dispatch loop on every scan. - Hostname auto-suggest: picking channel N on a default-hostname scanner (empty / "spoolsense" / "spoolsense-tN") flips to "spoolsense-tN" so multi-scanner deployments get unique mDNS names without thinking. - handleSpoolmanSynced gates the publish on TagKind::GenericUidTag so smart-tag formats (TigerTag, OT3D, OpenSpool, OPT) keep their existing flow — smart-tag U1 publish is Phase 2. Requires the U1 to have "Filament Detection: External" set in http://<printer-ip>/firmware-config/. Documented in .mex/context/direct-moonraker-mode.md. Builds clean on esp32dev, esp32s3zero, esp32c3, esp32s3devkitc.
…gment
Split the U1 direct-mode integration out of ApplicationManager into a
dedicated U1Manager singleton. Same external behavior, cleaner separation,
and now covers all 6 supported tag formats — not just generic UID.
Architecture:
ApplicationManager.handleSpoolDetected -> U1Manager.publishFromDetection
ApplicationManager.handleSpoolmanSynced -> U1Manager.publishFromSpoolmanSync
U1Manager (src/U1Manager.{h,cpp}) owns:
- U1FilamentInfo wire-format struct + builders
- per-material defaults (PLA/PETG/ABS/ASA/TPU/PVA/PC/PA hotend+bed)
- MAIN_TYPE/SUB_TYPE splitter (space + hyphen, e.g. "PETG-CF")
- HTTP POST to /printer/filament_detect/set
- 30s reachability backoff + 250ms mutex wait
- Pending-augment tracking (smart tag -> Spoolman fill-in)
Smart tag flow:
1. handleSpoolDetected -> publishFromDetection: builds info from on-tag
data (vendor, material, color, temps), applies per-material defaults
for any field that's still 0, POSTs immediately. Bambu, OpenSpool,
OPT, TigerTag, OT3D all flow through this path.
2. If the result is incomplete AND Spoolman is configured, registers a
pending augment. handleSpoolmanSynced then merges Spoolman fields
and re-POSTs only if Spoolman supplied something new.
Generic UID flow: single POST from publishFromSpoolmanSync(is_uid_lookup),
unchanged in spirit from the previous implementation.
MAIN_TYPE convention matches the firmware's own OpenSpool parser
(uppercase, e.g. "PLA"), so non-recognized variants like "PETG-CF" split
into MAIN_TYPE="PETG" + SUB_TYPE="CF" — gets firmware protocol mapping
for the base type plus descriptive sub-type display in Fluidd.
ApplicationManager shrinks by ~120 lines; U1 logic is now genuinely
separable (single file removal kills the feature cleanly).
Builds clean on esp32dev, esp32s3zero, esp32c3, esp32s3devkitc.
Address Ollama remote-review findings on U1Manager: 1. Switch the pending-augment UID compare from strcmp to strncmp bounded by the buffer size. Defensive against any producer of SpoolmanSyncedPayload that fails to null-terminate spool_id — strcmp would walk past the 17-byte buffer; strncmp can't. 2. Document the single-threaded-dispatch invariant in U1Manager.h. Both entry points are only called from ApplicationManager handlers, which run on the processMessages() loop. Internal state (moonrakerBackoffUntilMs_, pendingAugment_) is intentionally unguarded; cross-thread invocation would require revisiting both fields, not just adding atomics.
…-present + don't kill late augments Three CodeRabbit findings on the augment + UID-lookup paths: 1. publishFromSpoolmanSync no longer rebuilds U1FilamentInfo from scratch for smart tags. PendingAugment now caches the exact wire-format struct that POST 1 sent; POST 2 starts from that cache and overlays only non-empty Spoolman fields via overlaySpoolmanFields(). On-tag vendor/material/temps are preserved when Spoolman has gaps. The dropped (void)state comment masked a real regression where sparse Spoolman entries clobbered rich on-tag data with material defaults. 2. Generic-UID-tag publish (is_uid_lookup) now verifies the reader still holds the same tag before posting. If the user removed the tag during the Spoolman lookup (1-3s WiFi roundtrip is enough to fall behind a user's intent), we skip the POST instead of writing stale info to the U1 channel. Mirrors the writeback guard already in handleSpoolmanSynced for the NFC-writeback path. 3. Late-arriving sync for a previous tag no longer wipes the current pendingAugment. Scanning two smart tags within ~3 seconds was sabotaging tag B's augment because tag A's late SPOOLMAN_SYNCED would hit the mismatch branch and clear pendingAugment_.active. Now the mismatch branch just returns; only matching UID consumption or expiry can deactivate the augment. Refactor: - U1FilamentInfo moved from U1Manager.cpp anonymous namespace to U1Manager.h so PendingAugment can hold a copy. Type stays implementation-detail in spirit — only U1Manager.cpp references it. - want* flags removed from PendingAugment in favor of the cached struct; overlaySpoolmanFields() decides what to overwrite by comparing values. - buildFromSpoolmanSync simplified — no longer takes CurrentSpoolState; for the generic-UID path Spoolman is the only data source, and the smart-tag augment path doesn't use it (uses postedInfo + overlay). Builds clean on esp32dev, esp32s3zero, esp32c3, esp32s3devkitc.
Phase 1 of U1 direct-mode integration. Scanner pushes scan results to the U1's external filament-detection endpoint exposed by paxx12 Extended Firmware. No middleware, no Klipper macros — single HTTP POST per scan. - All 6 tag formats supported (OpenSpool, OPT, TigerTag, OT3D, Bambu, NFC+) - One scanner per toolhead (channel 0–3 in NVS) - Per-material temp defaults for tags missing data (PLA/PETG/ABS/etc.) - Spoolman augment fills gaps in on-tag data without overwriting good fields - 30s reachability backoff so an offline U1 doesn't block the dispatch loop Requires extended firmware develop branch + Filament Detection: External.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (9)
📝 WalkthroughWalkthroughThe PR adds Snapmaker U1 direct-mode integration to the firmware. It includes configuration UI for enabling U1 mode and selecting a toolhead channel, extends the configuration manager to persist these settings, implements a new U1Manager for publishing filament detection data to Moonraker with smart-tag parsing and Spoolman sync augmentation, and updates spool lifecycle handlers to invoke the U1Manager. Changes
Sequence Diagram(s)sequenceDiagram
participant NFC as NFC/Spool<br/>Detection
participant U1 as U1Manager
participant Moonraker as Moonraker API
participant Spoolman as Spoolman<br/>(if enabled)
NFC->>U1: publishFromDetection(SmartTagPayload)
U1->>U1: Parse material name (MAIN/SUB)<br/>Derive RGB, temp defaults
U1->>U1: Pack card UID
U1->>Moonraker: POST /filament/detect/set<br/>(U1FilamentInfo)
alt HTTP Success
Moonraker-->>U1: 200 OK
else HTTP Failure & Spoolman Enabled
U1->>U1: Cache as pending augment<br/>(UID, TTL)
end
sequenceDiagram
participant Spoolman as Spoolman Sync
participant U1 as U1Manager
participant Moonraker as Moonraker API
Spoolman->>U1: publishFromSpoolmanSync(SyncPayload, SpoolState)
alt Smart-Tag with Pending Augment
U1->>U1: Verify pending UID/expiry
U1->>U1: Overlay Spoolman fields<br/>onto cached info
U1->>U1: Check for changes
alt Changes Detected
U1->>Moonraker: POST augmented<br/>U1FilamentInfo
end
else Generic UID-Only Lookup
U1->>Moonraker: POST Spoolman-derived<br/>U1FilamentInfo
end
Moonraker-->>U1: Response
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 0/1 reviews remaining, refill in 60 minutes.Comment |
Summary
Release v1.7.5 — adds Snapmaker U1 direct-mode integration as the only user-visible change since v1.7.4.
Changes since v1.7.4 on dev
0cf9099feat(u1): direct-mode integration via /printer/filament_detect/set39f21f0refactor(u1): extract U1Manager + add smart-tag support, defaults, augment968728afix(u1): bound UID compare + document single-threaded invariant1c05c96fix(u1): address CodeRabbit review — preserve on-tag data + tag-still-present + don't kill late augments48459baMerge pull request feat(u1): Snapmaker U1 direct-mode integration #182: Snapmaker U1 direct-mode integrationCHANGELOG
See
CHANGELOG.mdfor the full entry. Single-feature release.Post-merge
After merge:
Summary by CodeRabbit
New Features
Documentation
Chores