v0.99.69 - 2026-05-23
Headline is a subscription regression fix from v0.99.68 — the Performance overlay's MCU printer.objects.subscribe was replacing the discovery subscription, so heater targets, print start, and progress updates stopped arriving on real hardware (Voron Trident + AFC bundle 9852XDXS). Also: a standalone fullscreen camera viewer under Settings → Hardware, AMS sensor toast suppression extended to HH/AFC/AD5X IFS/CFS, user-edited AD5X IFS slot color/material preserved against firmware re-emission (#965), and a friendlier installer banner for non-Pi SBCs using the pi package.
Added
- Standalone fullscreen camera viewer (Settings → Hardware → Camera) — opens an MJPEG stream without an on-screen CameraWidget. Visible only when the printer has a webcam, delegates to an attached widget if one is on-screen so mjpg-streamer's single-client limit doesn't break both streams, and tears down cleanly via AsyncLifetimeGuard + lv_draw_wait_for_finish (the cluster:pstat-async-delete avoidance pattern from #749). Shows a "Connecting Camera..." spinner until the first frame.
Fixed
- Heater targets, print start, and progress updates restored after v0.99.68 (Voron Trident + AFC bundle 9852XDXS) — MoonrakerPerformanceSource issued its own printer.objects.subscribe for MCU stats on connect, and per Moonraker "a new request will override a previous request," so it replaced the discovery subscription (heaters, fans, print_stats, virtual_sdcard, display_status, AFC, …). notify_status_update then stopped arriving for everything outside MCU; the UI looked frozen. MCU discovery now folds into MoonrakerDiscoverySequence and ships in the single union built by build_subscription_objects(...); the performance source registers a notify_status_update hook through subscribe_notifications instead of issuing a second subscribe. Also fixes a parser bug exposed by the field-narrowing: bytes_retransmit is nested inside last_stats (not at the top level), so MCU retransmit counts never updated in v0.99.68 either.
- AD5X IFS self-heals when the plugin macro turns out missing — three corrections to has_ifs_vars_ tracking. Klipper webhooks _do_query() returns {} for unknown objects with the key still present, so a status.contains("gcode_macro _ifs_vars") check was falsely true on stock ZMOD without lessWaste/bambufy installed; now requires a non-empty variables dict. When IFS_VARS mirror writes come back rejected with "// Unknown command:"X"", a latch demotes has_ifs_vars so the rest of the session takes the native-ZMOD path and stops echoing rejected gcodes on every Adventurer5M.json poll. A notify_klippy_ready listener re-queries after FIRMWARE_RESTART so adding or removing the plugin macro takes effect without restarting HelixScreen.
- User-edited slot color and material preserved on AD5X IFS (#965) — AD5X firmware re-emits the prior FFMInfo into Adventurer5M.json after print completion, and the OverwriteAlways auto-mirror was blindly clobbering both fields in the override. A HelixScreen-edited material would silently revert to whatever firmware re-emitted, persisted to the Moonraker DB and visible after restart. set_slot_info(persist=true) now tags both fields user-locked across all four AMS backends (IFS, Snapmaker, CFS, ACE); the mirror's OverwriteAlways path skips locked fields. Locks round-trip through lane_data as helix_locked_color / helix_locked_material, and legacy records load with locks pessimistic-defaulted to true so existing user data survives the upgrade. Trade-off: external Mainsail-console / native-LCD edits no longer auto-propagate over a slot the user set in HelixScreen — clear_slot_override is the escape hatch.
- AMS sensor toast suppression extended to HH, AFC, AD5X IFS, and CFS — a fresh Happy Hare or AFC install pelted users with "Filament sensor available. Add to config for runout detection?" toasts for sensors the AMS backend already owns. The substring filter caught mmu/afc/gate/lane patterns, but HH uses conventional names (extruder, toolhead, filament_tension, filament_compression) and AFC uses tool_start/tool_end plus user-named per-lane sensors. New discovery-aware is_ams_sensor(name, PrinterDiscovery&) consults the detected backend; for AD5X IFS it suppresses ifs_port_sensor*, ifs_motion_sensor, head_switch_sensor; for CFS it suppresses the bare filament_sensor conditional on has_mmu() so non-CFS users with that name still get the toast. The Settings → Sensors list and the wizard's filament-sensor selection step migrate to the same filter so HH/AFC-managed sensors no longer appear as standalone, user-configurable entries in either flow.
- Installer banner leads with hardware label on non-Pi SBCs — QIDI Q2/Plus, BTT CB1, MKS-Pi, etc. all install the pi package (generic ARM Linux build), but "Detected platform: pi" read as a misidentification to users whose printer says QIDI on the lid. The banner now leads with the friendly hardware label and reframes "pi" as the install package. Actual Raspberry Pi owners keep the original wording. Banner extracted into print_platform_banner() with 11 new bats cases covering real Pi, QIDI/BTT/MKS on pi & pi32, and five non-Pi platforms.