Commit Graph
87 Commits
Author SHA1 Message Date
maziggy 5fe4134d86 Reduce SpoolBuddy kiosk CPU/memory pressure
Add Chromium flags to cut overhead on Pi: disable extensions, crash
  reporter, background timer throttling, renderer backgrounding, and cap
  V8 heap at 128MB. Mask (not just disable) stripped system services to
  prevent socket/dbus reactivation, and add xdg-permission-store to the
  disable list. Remove chromium and upower from strip_packages since the
  kiosk needs them — they were being uninstalled then immediately
  reinstalled on every run.
2026-03-27 13:32:49 +01:00
maziggy 70382ec55c Add Chromium flags to cut overhead on Pi: disable extensions, crash
reporter, background timer throttling, renderer backgrounding, and cap
  V8 heap at 128MB. Also mask (not just disable) stripped system services
  to prevent socket/dbus reactivation, and add xdg-permission-store to
  the disable list.
2026-03-27 13:28:12 +01:00
maziggy 7a0ea8faed Revert " Optimize SpoolBuddy kiosk performance on Raspberry Pi"
This reverts commit 24cda842af.
2026-03-27 12:00:14 +01:00
maziggy a8b50e809f Optimize SpoolBuddy kiosk performance on Raspberry Pi 2026-03-27 11:45:28 +01:00
maziggy 24cda842af Optimize SpoolBuddy kiosk performance on Raspberry Pi
Replace Chromium with cog (WPE WebKit) for the kiosk browser. Cog is
  purpose-built for embedded kiosk displays with a fraction of Chromium's
  CPU and memory footprint on Pi hardware.

  Add React Query `select` to SpoolBuddyLayout and SpoolBuddyDashboard
  printer status queries so only `connected` is extracted. Temperature,
  fan, and progress changes no longer trigger re-renders on every MQTT
  tick.

  Expand service/package stripping to disable pipewire audio stack, CUPS
  printing, rpcbind, upower, polkit, accounts-daemon, xdg-desktop-portal,
  and mpris-proxy. Add user-level service masking for pipewire/portals.

  Update SSH update cache clearing to handle both WPE WebKit and legacy
  Chromium cache paths.
2026-03-27 11:43:55 +01:00
maziggy 54c67f9e4e Optimize SpoolBuddy kiosk performance on Raspberry Pi
Override Debian's default Chromium flags via /etc/chromium.d/spoolbuddy-kiosk
  to disable GPU rasterization, enable low-end device mode, and disable smooth
  scrolling/background networking. The system default --enable-gpu-rasterization
  conflicted with per-launch flags — the new config replaces all system defaults
  so kiosk flags take effect cleanly.

  Expand service/package stripping to disable pipewire audio stack, CUPS
  printing, rpcbind, upower, polkit, accounts-daemon, xdg-desktop-portal,
  and mpris-proxy. Add user-level service masking for pipewire/portals
  that system-level disable misses.
2026-03-27 10:44:58 +01:00
maziggy 26c2549a56 Optimize SpoolBuddy kiosk performance on Raspberry Pi
Add Chromium performance flags (disable-gpu-rasterization,
  enable-low-end-device-mode, disable-smooth-scrolling,
  disable-background-networking, disable-dev-shm-usage) to reduce
  CPU load from ~54% to manageable levels on Pi 4B.

  Expand service/package stripping to disable pipewire audio stack,
  CUPS printing, rpcbind, upower, polkit, accounts-daemon,
  xdg-desktop-portal, and mpris-proxy. Add user-level service
  masking for pipewire/portals that system-level disable misses.
2026-03-27 10:26:56 +01:00
Keybored eb3450b1d0 Spoolbuddy init and diagnostic improvements (#814)
Spoolbuddy init and diagnostic improvements (#814)
2026-03-26 16:16:09 +01:00
maziggy e4999f48fb Polish SpoolBuddy boot splash and reduce initramfs rebuilds
New splash shows only the SpoolBuddy logo with green glow bloom,
  radial gradient, light rays, and vignette. Removed Bambuddy branding.
  Includes generator script for easy customization.

  Defers initramfs rebuild during install until after Plymouth theme
  is configured, avoiding redundant rebuilds from apt hooks.
2026-03-26 13:05:20 +01:00
maziggy 12c2b57962 Polish SpoolBuddy boot splash and reduce initramfs rebuilds
New splash shows only the SpoolBuddy logo with green glow bloom,
  radial gradient, light rays, and vignette. Removed Bambuddy branding.
  Includes generator script for easy customization.

  Defers initramfs rebuild during install until after Plymouth theme
  is configured, avoiding redundant rebuilds from apt hooks.
2026-03-26 13:00:06 +01:00
maziggy b1f2670058 Revert install.sh to Plymouth, keep polished splash
Reverts the fim/fbi experiment — Plymouth is the only splash tool
  that reliably handles Pi KMS/DRM from early boot. install.sh is
  restored to the original Plymouth setup. The new polished splash
  image and generator script are kept.
2026-03-26 12:52:14 +01:00
maziggy 58b5e3ae09 Replace Plymouth with fim for SpoolBuddy boot splash
Plymouth ran as a persistent daemon throughout boot, consuming memory
  and competing for framebuffer allocation. fim renders via DRM (Pi KMS
  doesn't expose a usable legacy framebuffer), displays the image, and
  exits — zero ongoing resource cost.

  New splash image shows only the SpoolBuddy logo with baked-in glow,
  radial gradient, light rays, and vignette effects (66KB vs 205KB).
  Install script auto-purges Plymouth on existing installs in a single
  pass to avoid redundant initramfs rebuilds.
2026-03-26 12:22:29 +01:00
maziggy 387aafaee4 Replace Plymouth with fbi for SpoolBuddy boot splash
Plymouth ran as a persistent daemon throughout boot, consuming memory
  and competing for framebuffer allocation. fbi writes pixels directly
  to the framebuffer and exits — zero ongoing resource cost.

  New splash image shows only the SpoolBuddy logo with baked-in glow,
  radial gradient, light rays, and vignette effects (66KB vs 205KB).
  Install script auto-purges Plymouth on existing installs in a single
  pass to avoid redundant initramfs rebuilds.
2026-03-26 12:10:42 +01:00
maziggy 4c7141f738 Replace Plymouth with fbi for SpoolBuddy boot splash
Plymouth ran as a persistent daemon throughout boot, consuming memory
  and competing for framebuffer allocation. fbi writes pixels directly
  to the framebuffer and exits — zero ongoing resource cost.

  New splash image shows only the SpoolBuddy logo with baked-in glow,
  radial gradient, light rays, and vignette effects (66KB vs 205KB).
  Install script auto-removes Plymouth on existing installs.
2026-03-26 12:03:49 +01:00
maziggy 4521366a5b Fix Read Tag diagnostic failing on NTAG tags
The read_tag.py diagnostic script had stale PN5180 NTAG methods: TX CRC
  was off (should be on), no Crypto1 clear, no IDLE→TRANSCEIVE state
  reset. Multi-batch reads failed because the PN5180 enters an
  unrecoverable state after an NTAG READ — requires a full GPIO hardware
  reset between 4-page batches. Also rejected SAK 0x04 as unsupported,
  and failed hard when reading past the end of smaller tags (MIFARE
  Ultralight has 16 pages vs NTAG's 44+). Synced write methods with
  daemon.
2026-03-26 10:32:44 +01:00
maziggy d341b86748 Fix Read Tag diagnostic failing on NTAG tags
The read_tag.py diagnostic script had stale PN5180 NTAG methods: TX CRC
  was off (should be on), no Crypto1 clear, no IDLE→TRANSCEIVE state
  reset. Multi-batch reads failed because the PN5180 enters an
  unrecoverable state after an NTAG READ — requires a full GPIO hardware
  reset between 4-page batches. Also rejected SAK 0x04 as unsupported.
  Synced write methods with daemon.
2026-03-26 10:31:18 +01:00
maziggy cd92d0099e Fix Read Tag diagnostic failing on NTAG tags
The read_tag.py diagnostic script had stale PN5180 NTAG methods: TX CRC
  was off (should be on), no Crypto1 clear, no IDLE→TRANSCEIVE state
  reset, and multi-batch reads failed because the PN5180 can't issue
  consecutive NTAG READs without a full RF power cycle. Added extended-
  timing reactivation (50ms gaps vs 10ms) between 4-page batches. Also
  rejected SAK 0x04 as unsupported. Synced write methods with daemon.
2026-03-26 10:28:25 +01:00
maziggy 0aeee26b3e Fix Read Tag diagnostic failing on NTAG tags
The read_tag.py diagnostic script had stale PN5180 NTAG methods: TX CRC
  was off (should be on), no Crypto1 clear, no IDLE→TRANSCEIVE state
  reset, and multi-batch reads failed because subsequent READ commands
  need a full state machine reset between batches. Also rejected SAK 0x04
  as unsupported. Synced register setup and write methods with daemon.
2026-03-26 10:25:41 +01:00
maziggy a321a709b5 Fix Read Tag diagnostic failing on NTAG tags
The read_tag.py diagnostic script had stale PN5180 NTAG methods: TX CRC
  was off (should be on), no Crypto1 clear, no IDLE→TRANSCEIVE state
  reset, and the PN5180 drops the card after each READ batch requiring
  reactivation between 4-page reads. Also rejected SAK 0x04 as
  unsupported. Synced register setup with daemon and added per-batch
  card reactivation.
2026-03-26 10:23:07 +01:00
maziggy 1c96b00a6b Fix Read Tag diagnostic failing on NTAG tags
The read_tag.py diagnostic script had stale PN5180 NTAG methods that
  were never synced with the daemon's fixes: TX CRC was off (should be
  on), no Crypto1 clear, no IDLE→TRANSCEIVE state reset, and unreliable
  ACK/verification logic. Also rejected SAK 0x04 as unsupported. Synced
  ntag_read_pages, ntag_write_page, and ntag_write_pages with daemon.
2026-03-26 10:17:17 +01:00
maziggy e237d3ba28 Fix Read Tag diagnostic rejecting SAK 0x04 NTAG tags
The read_tag.py diagnostic script only accepted SAK 0x00 for NTAG,
  showing "Unsupported tag type" for chips reporting SAK 0x04 (MIFARE
  Ultralight family). The daemon already handled both values — the
  diagnostic was missed. Now accepts both 0x00 and 0x04.
2026-03-26 10:12:09 +01:00
maziggy 77cb7158d2 Add SpoolBuddy System tab with live OS stats from Raspberry Pi
The daemon now collects CPU temp, core count, load average, memory/disk
  usage, OS info, and system uptime every heartbeat using stdlib-only reads
  from /proc and /sys. Stats are sent as a JSON blob in the heartbeat
  payload, stored in a new system_stats TEXT column, and displayed in a
  new "System" tab in SpoolBuddy Settings with color-coded usage bars.
2026-03-26 09:57:09 +01:00
maziggy c1c31d8d91 Skip NTAG post-write verification — PN5180 read-back unreliable
The PN5180 cannot read more than 4 NTAG pages after a batch write:
  the second READ command (page 8+) returns rx_status=0 regardless of
  state machine reset strategy. The write itself succeeds (tag ACKs
  via SOF on every page). Remove verification and trust the writes.
2026-03-25 13:34:53 +01:00
maziggy a59c81d6a6 Fix NTAG read loop: IDLE→TRANSCEIVE once, set_transceive_mode after
Repeated IDLE→TRANSCEIVE resets inside the read loop broke the card
  session after the first READ (page 8 returned rx_status=0). Match
  the activate_type_a pattern: IDLE→TRANSCEIVE once before the loop,
  set_transceive_mode() for subsequent iterations.
2026-03-25 13:33:04 +01:00
maziggy 85ffb9e01f Fix NTAG read: apply same IDLE→TRANSCEIVE state machine reset
The verification read after writing failed because ntag_read_pages()
  used set_transceive_mode() which was a no-op when already in
  TRANSCEIVE. Apply the same IDLE→TRANSCEIVE reset pattern used in the
  write path, clear Crypto1, and add diagnostic logging.
2026-03-25 13:30:09 +01:00
maziggy 918dec4c19 Skip NTAG write ACK check — PN5180 can't capture 4-bit response
IRQ logging revealed the tag IS responding (RX_SOF_DET set) but the
  PN5180 cannot capture the 4-bit ACK as a complete frame — RX_IRQ
  never fires and RX_STATUS stays zero. Skip per-page ACK checking
  and rely on the read-back verification in ntag_write_pages().
2026-03-25 13:27:31 +01:00
maziggy 31ca2e7ddf Fix NTAG write: reset PN5180 state machine before WRITE command
The PN5180 transceive state machine wasn't being reset between the
  SELECT (from reactivate_card) and the WRITE command — just re-setting
  the TRANSCEIVE bits was a no-op. Use IDLE→TRANSCEIVE transition like
  activate_type_a does. Also clear Crypto1 bit and add IRQ status
  logging.
2026-03-25 13:24:57 +01:00
maziggy bae394d277 Add debug logging to NTAG write/verify path
Temporary diagnostics to identify which step of the NTAG write
  fails: per-page ACK status, reactivation, read-back, or data
  mismatch. Enable DEBUG level for pn5180 module.
2026-03-25 13:21:27 +01:00
maziggy 72536c93a0 Fix NTAG write ACK detection for 4-bit response
The NTAG WRITE ACK is 4 bits (0x0A), not a full byte. The PN5180
  RX_STATUS register reports 0 complete bytes with 4 extra bits, but
  the check only looked at the byte count — returning False on every
  successful write. Check both byte and bit fields of RX_STATUS.
  Also bump post-write delay from 5ms to 10ms for margin.
2026-03-25 13:18:41 +01:00
maziggy f4d8e1ecd3 Fix SpoolBuddy NFC write failing on NTAG 213/215/216 tags
Three issues:

  1. SAK gate too strict — NTAG chips can report SAK 0x04 (MIFARE
     Ultralight family) instead of 0x00. Accept both in nfc_reader.py
     and main.py.

  2. TX CRC disabled for NTAG WRITE — the NTAG spec requires CRC on
     the WRITE command frame. Enable TX CRC in ntag_write_page().

  3. TX CRC disabled for NTAG READ — the post-write verification read
     also failed because ntag_read_pages() sent the READ command
     without CRC. Enable TX CRC there too.
2026-03-25 13:15:45 +01:00
maziggy 9d4f57d54d Fix SpoolBuddy NFC write failing on NTAG 213/215/216 tags
Two issues:

  1. SAK gate too strict — NTAG chips can report SAK 0x04 (MIFARE
     Ultralight family) instead of 0x00. Accept both in nfc_reader.py
     and main.py.

  2. TX CRC disabled during WRITE — the NTAG WRITE command (0xA2)
     requires a CRC on the frame. The PN5180 was sending without CRC,
     causing the tag to NAK every write. Enable TX CRC for writes
     (RX CRC stays off for the 4-bit ACK).
2026-03-25 13:12:57 +01:00
maziggy f71367bb4e Fix SpoolBuddy NFC write rejecting NTAG 215 tags with SAK=0x04
NTAG 213/215/216 chips can report SAK 0x04 (MIFARE Ultralight family)
  instead of 0x00 during anticollision. Accept both values for NTAG
  detection and write operations in nfc_reader.py and main.py.
2026-03-25 13:10:11 +01:00
maziggy 3c1fdd13b9 Added back debug logs to Spoolbuddy test scripts 2026-03-25 12:16:49 +01:00
maziggy d5c520dd71 Added back debug logs to Spoolbuddy test scripts 2026-03-25 12:15:29 +01:00
maziggy 74387b7c38 Added back debug logs to Spoolbuddy test scripts 2026-03-25 12:15:22 +01:00
maziggy f96d211612 Added back debug logs to Spoolbuddy test scripts 2026-03-25 12:13:31 +01:00
maziggy 2b1fe03159 Fix SpoolBuddy scale first reading and extract hardware drivers
The NAU7802 ADC returns a stale max-scale value (0x7FFFFF) on its
  first conversion after power-up, polluting the moving average and
  making the initial weight report wildly inaccurate. Flush the first
  reading during init().

  Also extract both hardware drivers out of diagnostic scripts into
  proper daemon modules:
  - NAU7802 scale driver: scripts/scale_diag.py -> daemon/nau7802.py
  - PN5180 NFC driver: scripts/read_tag.py -> daemon/pn5180.py

  The production daemon was importing driver classes from test scripts
  since the original SpoolBuddy commit. Diagnostic scripts now import
  from the driver modules. Removed the sys.path hack from main.py.
2026-03-25 11:57:28 +01:00
maziggy a5ea3f599a Minor Spoolbuddy install.sh fixes 2026-03-25 10:24:47 +01:00
maziggy f96b9ded56 Add WiFi safeguard and apt upgrade to SpoolBuddy install script
Install script now runs apt-get upgrade -y after installing system
  packages. A WiFi safeguard (APT hook + helper script) is installed
  first, backing up NetworkManager connections before dpkg and restoring
  them if wiped — prevents headless Pis from losing WiFi during upgrades.
2026-03-25 10:22:22 +01:00
maziggy cb31a6cd33 Add apt upgrade to SpoolBuddy install script
Runs apt-get upgrade -y after installing system packages and the WiFi
  safeguard hook. Ensures the Pi is fully up to date before deploying
  SpoolBuddy, and the WiFi safeguard protects NM connections during
  the upgrade.
2026-03-25 10:14:16 +01:00
maziggy 53da037048 Add WiFi safeguard to SpoolBuddy install script
APT hook backs up NetworkManager WiFi connections before dpkg runs
  and restores them if they get wiped. Prevents headless SpoolBuddy
  Pis from losing WiFi after apt upgrade (observed with Bookworm
  kernel/raspi-config updates clearing system-connections/).
2026-03-25 09:53:14 +01:00
Keybored 6e648804fc [Feature] Spoolbuddy Fixes and Improvements (#787)
[Feature] Spoolbuddy Fixes and Improvements (#787)
2026-03-24 11:56:33 +01:00
maziggy 364b02b8ac Housekeeping 2026-03-23 15:44:49 +01:00
maziggy a922c18a41 ● Disable Chromium disk cache in SpoolBuddy kiosk
After updates, the kiosk browser showed stale frontend assets from
  Chromium's disk cache even after restarting. Added --disk-cache-size=0
  to the launch flags — the kiosk loads a single page from the local
  network so caching provides no benefit.
2026-03-23 14:11:21 +01:00
maziggy db43218785 Fix SpoolBuddy kiosk launching before network is ready
The getty@tty1 autologin had no network dependency, so the labwc/Chromium
  kiosk chain started before connectivity was up — showing a connection
  error for 10-15 seconds. Added After=network-online.target to the
  autologin override so the browser has network when it launches.
2026-03-23 14:04:55 +01:00
maziggy 136ecb7c92 Replace SpoolBuddy self-update with SSH-based updates from Bambuddy
The daemon's self-update mechanism (git fetch/reset on its own code) was
  fragile: .git permission errors, self-modifying code mid-run, hardcoded
  main branch. Bambuddy now SSHes into the SpoolBuddy Pi and drives the
  update remotely — matching its own branch, with step-by-step progress
  via WebSocket. After updating the daemon, the kiosk browser is also
  restarted so it loads the updated frontend.

  SSH key pairing is automatic: Bambuddy generates an ED25519 keypair and
  returns the public key in the registration response. The daemon deploys
  it to authorized_keys on first connect — no manual setup needed.

  Changes:
  - New: backend/app/services/spoolbuddy_ssh.py
  - Rewritten: trigger_daemon_update endpoint (SSH instead of pending_command)
  - New: GET /spoolbuddy/ssh/public-key endpoint
  - Auto SSH key deployment via registration response + daemon
  - Removed: daemon _perform_update() and cmd=="update" handler
  - Install script: bash shell, sudoers for daemon + kiosk restart, .ssh/ setup
  - Dockerfile: added openssh-client
  - Frontend: SSH key display, force update button
  - Fixed: update check compares APP_VERSION, not GitHub releases
  - Fixed: kiosk browser restart after update
2026-03-23 13:46:45 +01:00
maziggy 5e9481859b Replace SpoolBuddy self-update with SSH-based updates from Bambuddy
The daemon's self-update mechanism (git fetch/reset on its own code) was
  fragile: .git permission errors, self-modifying code mid-run, hardcoded
  main branch. Bambuddy now SSHes into the SpoolBuddy Pi and drives the
  update remotely — matching its own branch, with step-by-step progress
  via WebSocket.

  SSH key pairing is automatic: Bambuddy generates an ED25519 keypair and
  returns the public key in the registration response. The daemon deploys
  it to authorized_keys on first connect — no manual setup needed.

  - New: backend/app/services/spoolbuddy_ssh.py (keypair, SSH commands, update orchestration)
  - Rewritten: trigger_daemon_update endpoint uses SSH instead of pending_command
  - New: GET /spoolbuddy/ssh/public-key endpoint for manual pairing
  - Removed: daemon _perform_update() and cmd=="update" heartbeat handler
  - Updated: install.sh — bash shell, sudoers for systemctl restart, .ssh/ setup
  - Updated: Dockerfile — added openssh-client
  - Updated: frontend — SSH key display, force update button
  - Fixed: update check now compares against APP_VERSION, not GitHub releases
2026-03-23 13:32:42 +01:00
maziggy bc1bba078b Replace SpoolBuddy self-update with SSH-based updates from Bambuddy
The daemon's self-update mechanism (git fetch/reset on its own code) was
  fragile: .git permission errors, self-modifying code mid-run, hardcoded
  main branch. Bambuddy now SSHes into the SpoolBuddy Pi and drives the
  update remotely — matching its own branch, with step-by-step progress
  via WebSocket. Install script updated with SSH access, sudoers entry,
  and --ssh-pubkey flag for pairing.
2026-03-23 12:51:21 +01:00
maziggy 18700cf5da Fix SpoolBuddy daemon reporting stale version in update check
The daemon had a hardcoded __version__ = "0.2.2b1" that was never
  bumped, causing the update check to always show an update available.
  Changed to read APP_VERSION from backend/app/core/config.py at import
  time so the daemon version stays in sync automatically.
2026-03-22 13:08:45 +01:00
maziggy d750e8f0e0 Added Spoolbuddy frontend/backend tests 2026-03-22 12:55:35 +01:00