Skip to content

Release v1.7.5 — Snapmaker U1 direct-mode integration#183

Merged
sjordan0228 merged 6 commits into
mainfrom
release/v1.7.5
Apr 30, 2026
Merged

Release v1.7.5 — Snapmaker U1 direct-mode integration#183
sjordan0228 merged 6 commits into
mainfrom
release/v1.7.5

Conversation

@sjordan0228
Copy link
Copy Markdown
Contributor

@sjordan0228 sjordan0228 commented Apr 30, 2026

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

  • 0cf9099 feat(u1): direct-mode integration via /printer/filament_detect/set
  • 39f21f0 refactor(u1): extract U1Manager + add smart-tag support, defaults, augment
  • 968728a fix(u1): bound UID compare + document single-threaded invariant
  • 1c05c96 fix(u1): address CodeRabbit review — preserve on-tag data + tag-still-present + don't kill late augments
  • 48459ba Merge pull request feat(u1): Snapmaker U1 direct-mode integration #182: Snapmaker U1 direct-mode integration

CHANGELOG

See CHANGELOG.md for the full entry. Single-feature release.

Post-merge

After merge:

  1. Push tag `v1.7.5` on the merge commit → triggers `Build and Release Firmware` workflow
  2. Workflow builds 4 envs, creates GitHub Release, dispatches to spoolsense.org
  3. spoolsense.org auto-updates web-flasher manifests + binaries (recently-validated dispatch path)

Summary by CodeRabbit

  • New Features

    • Added Snapmaker U1 direct-mode integration with filament detection publishing via HTTP
    • Added U1 configuration UI with enable toggle and toolhead channel selection (T0–T3)
    • Implemented automatic hostname suggestion based on selected channel
    • Added support for temperature defaults and Spoolman sync with U1 integration
  • Documentation

    • Updated changelog for version 1.7.5 release
  • Chores

    • Bumped firmware version to 1.7.5

sjordan0228 and others added 6 commits April 29, 2026 16:59
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.
@sjordan0228 sjordan0228 merged commit 62ff051 into main Apr 30, 2026
2 checks passed
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: abf938dc-f2f1-475e-be73-c5c294fcf471

📥 Commits

Reviewing files that changed from the base of the PR and between bc672aa and 6e5cbe3.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • platformio.ini
  • src/ApplicationManager.cpp
  • src/ConfigHTML.h
  • src/ConfigurationManager.cpp
  • src/ConfigurationManager.h
  • src/U1Manager.cpp
  • src/U1Manager.h
  • src/WebServerManager.cpp

📝 Walkthrough

Walkthrough

The 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

Cohort / File(s) Summary
Version & Release
CHANGELOG.md, platformio.ini
Version bump to 1.7.5; release notes document U1 direct-mode integration, filament detection over HTTP, and channel/temperature configuration behavior.
U1 Manager Core
src/U1Manager.h, src/U1Manager.cpp
New U1Manager singleton implementing filament detection publishing with smart-tag material parsing, RGB/temperature derivation, Spoolman sync augmentation, Moonraker HTTP posting, and pending augment caching with TTL-based expiry.
Configuration System
src/ConfigurationManager.h, src/ConfigurationManager.cpp, src/WebServerManager.cpp
Extended to load, save, and expose U1 settings (enable flag and toolhead channel 0–3) via NVS and REST API endpoints with validation and clamping.
UI/Configuration Form
src/ConfigHTML.h
Added U1 integration UI: enable checkbox, channel selector (T0–T3) with conditional visibility, and hostname auto-suggest logic (spoolsense-t<channel>) on channel change.
Application Lifecycle Hooks
src/ApplicationManager.cpp
Integrated U1Manager entry points: publishFromDetection invoked on spool detection and publishFromSpoolmanSync invoked after Spoolman sync completion, excluding NATIVE_TEST builds.

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
Loading
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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • #182: Introduces the identical U1Manager integration changes across the same files (ApplicationManager, ConfigurationManager, WebServer, ConfigHTML).
  • #58: Modifies ApplicationManager::handleSpoolmanSynced to augment temperature handling alongside U1Manager publishing calls.
  • #45: Extends ApplicationManager spool detection and sync flow with additional NFC/Spoolman state handling that overlaps with U1Manager invocation points.

Suggested labels

size/XL

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/v1.7.5

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.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added the size/XL Extra large change (500+ lines) label Apr 30, 2026
@sjordan0228 sjordan0228 deleted the release/v1.7.5 branch May 10, 2026 22:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XL Extra large change (500+ lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant