tuanchris d0fae4a477 release: Dune Weaver 5.0.0 5 일 전
..
fonts d0fae4a477 release: Dune Weaver 5.0.0 5 일 전
models d0fae4a477 release: Dune Weaver 5.0.0 5 일 전
qml d0fae4a477 release: Dune Weaver 5.0.0 5 일 전
scripts d499747f90 Add kiosk code (#89) 9 달 전
.env.example 9fe64d2cce feat(touch): wire touch app directly to FluidNC firmware HTTP API 1 주 전
.gitattributes d499747f90 Add kiosk code (#89) 9 달 전
.gitignore 9fe64d2cce feat(touch): wire touch app directly to FluidNC firmware HTTP API 1 주 전
FIRMWARE_MIGRATION.md 9fe64d2cce feat(touch): wire touch app directly to FluidNC firmware HTTP API 1 주 전
RASPBERRY_PI_SETUP.md d499747f90 Add kiosk code (#89) 9 달 전
README.md d0fae4a477 release: Dune Weaver 5.0.0 5 일 전
backend.py d0fae4a477 release: Dune Weaver 5.0.0 5 일 전
configure-boot.sh d499747f90 Add kiosk code (#89) 9 달 전
discovery.py 9fe64d2cce feat(touch): wire touch app directly to FluidNC firmware HTTP API 1 주 전
dune-weaver-touch.desktop d499747f90 Add kiosk code (#89) 9 달 전
dune-weaver-touch.service 065e8d2b07 Native deployment, zero-SSH experience, WiFi hotspot, and security modes (#121) 4 달 전
firmware_client.py d0fae4a477 release: Dune Weaver 5.0.0 5 일 전
install-service.sh d499747f90 Add kiosk code (#89) 9 달 전
install.sh 4ef0f1dd00 Revert to EGLFS backend, keep Pi 5 QML rotation 6 달 전
main.py d0fae4a477 release: Dune Weaver 5.0.0 5 일 전
png_cache_manager.py 5a8083d14a feat: Complete React UI rewrite with new frontend architecture (#112) 5 달 전
requirements.txt 9fe64d2cce feat(touch): wire touch app directly to FluidNC firmware HTTP API 1 주 전
run.sh 9fe64d2cce feat(touch): wire touch app directly to FluidNC firmware HTTP API 1 주 전
setup-autologin.sh d499747f90 Add kiosk code (#89) 9 달 전
setup-autostart.sh d499747f90 Add kiosk code (#89) 9 달 전
setup_kiosk.sh d499747f90 Add kiosk code (#89) 9 달 전
thr_preview.py d0fae4a477 release: Dune Weaver 5.0.0 5 일 전

README.md

Dune Weaver Touch Interface

A PySide6/QML touch interface for the Dune Weaver sand table. It talks directly to the table's FluidNC firmware over its stateless HTTP/JSON API — there is no separate host (Raspberry Pi FastAPI) service in between.

Connecting to the table

The firmware is headless and advertises itself over mDNS. On launch the app:

  1. Auto-discovers tables via mDNS (_http._tcp advertisements with model=dune-weaver). If exactly one is found it connects automatically; otherwise pick one from the Control page's table list (tap Refresh to re-scan).
  2. Pin a table by setting DUNE_WEAVER_URL in .env (e.g. DUNE_WEAVER_URL=dunetable.local or an IP). This skips discovery.

The chosen table is remembered in touch_settings.json.

How it maps to the firmware API

  • Status is polled from GET /sand_status (~1 Hz) instead of a WebSocket.
  • Actions go out as $... commands via /command and the /sand_* routes (run/stop/pause/resume/home/goto/feed/LED).
  • Patterns come from GET /sand_patterns; previews are rendered locally and cached under preview_cache/. The .thr source is read from the co-located backend catalog (../patterns/, matched by path suffix / unique basename) when available — fetching from the board's SD (/sd/patterns/...) is the slow fallback for board-only patterns.
  • Password-protected boards are supported: the $Sand/Password key is stored (base64) in touch_settings.json and sent as X-Sand-Key on every request; set it under Control → Table Connection. 503 busy: low memory responses are retried with backoff, and the clock sync pushes epoch + POSIX timezone (quiet-hours/autostart schedules run on board-local time).
  • Playlists are .txt files on the SD card — listed via GET /sand_playlists, read from /sd/playlists/..., and created/edited by uploading/deleting files.
  • LEDs use the firmware's named effect/palette catalogue ($LED/* / /sand_led).
  • Screen / LCD backlight control stays local to the touch host (sysfs + sudo scripts).

See the firmware's API.md for the full contract.

Features

  • Five pages: Browse, Playlists, Control, Light (LED ring), and Now Playing
  • Pattern Browsing: grid of circular sand-dish previews with search
  • Now Playing: progress drawn as an ember arc around the live pattern disc, with the ball as the moving endpoint — plus transport and speed controls
  • Table Control: mDNS table discovery, movement, auto-play, screen settings
  • "Table at night" design system: warm basalt/bone night palette (default) and a sand day palette, one amber accent, all defined in qml/components/ThemeManager.qml; bundled Outfit + Material Icons Round fonts in fonts/ (registered in main.py, no system fonts needed)
  • Touch Optimized: 48px+ targets, pill controls, linuxfb-safe (no effects layers)

Architecture

  • Pattern Browsing: GET /sand_patterns on the table; .thr previews rendered locally
  • Execution Control: firmware $... commands via /command + /sand_* routes
  • Status Monitoring: polling GET /sand_status (~1 Hz)
  • Navigation: StackView-based page navigation

Key modules

  • firmware_client.py — shared async HTTP client + LED/clear-mode maps (singleton)
  • discovery.py — mDNS table discovery (zeroconf; degrades gracefully if absent)
  • thr_preview.py — renders .thr → cached PNG previews
  • backend.py — QML-facing controller (status poll, actions, LEDs, playlists, local screen)
  • models/PatternModel / PlaylistModel, both firmware-backed

Quick Installation (Auto-Start Setup)

One command to set up everything for kiosk/production use:

sudo ./install.sh

This will:

  • ✅ Create Python virtual environment with dependencies (venv/)
  • ✅ Install system scripts for screen control (/usr/local/bin/screen-on, screen-off, touch-monitor)
  • ✅ Set up systemd service for auto-start on boot
  • ✅ Configure kiosk optimizations (clean boot, auto-login)
  • ✅ Enable automatic startup

Service Management

# Control the service
sudo systemctl start dune-weaver-touch    # Start now
sudo systemctl stop dune-weaver-touch     # Stop service
sudo systemctl status dune-weaver-touch   # Check status
sudo journalctl -u dune-weaver-touch -f   # View logs

# Disable auto-start
sudo systemctl disable dune-weaver-touch

Manual Installation (Development)

  1. Create virtual environment and install dependencies:

    python3 -m venv venv
    source venv/bin/activate  # or: . venv/bin/activate
    pip install -r requirements.txt
    
  2. Power on the sand table and make sure it's on the same network (or set DUNE_WEAVER_URL in .env to pin its address).

  3. Run the touch interface:

    ./run.sh              # Uses virtual environment automatically
    # OR manually:
    ./venv/bin/python main.py
    

Advanced Setup Options

For custom installations:

sudo ./setup-autostart.sh

Choose from multiple setup options including systemd service, desktop autostart, or kiosk optimizations.

Project Structure

dune-weaver-touch/
├── main.py                     # Application entry point (fonts, QML engine)
├── backend.py                  # Backend controller (status poll, actions, LEDs)
├── fonts/                      # Bundled Outfit + Material Icons Round fonts
├── models/
│   ├── pattern_model.py        # Pattern list model (firmware-backed)
│   └── playlist_model.py       # Playlist model (firmware-backed)
├── qml/
│   ├── main.qml                    # Main window, tab navigation, error dialog
│   ├── pages/
│   │   ├── ModernPatternListPage.qml  # Browse: grid + search
│   │   ├── PatternDetailPage.qml      # Pattern detail: clear mode + play
│   │   ├── ModernPlaylistPage.qml     # Playlists: list, detail, settings
│   │   ├── PatternSelectorPage.qml    # Add-to-playlist pattern picker
│   │   ├── TableControlPage.qml       # Connection, movement, system settings
│   │   ├── LedControlPage.qml         # Light: power, effects, ball tracker
│   │   └── ExecutionPage.qml          # Now Playing: progress ring + transport
│   └── components/
│       ├── ThemeManager.qml        # Design tokens (palettes, type, spacing)
│       ├── Icon.qml                # Material icon glyph by name
│       ├── ModernControlButton.qml # Pill button (filled / outlined)
│       ├── ChoiceChip.qml          # Selectable option chip
│       ├── DwSlider.qml / DwSwitch.qml / SectionLabel.qml / SettingsCard.qml
│       ├── ModernPatternCard.qml   # Pattern card with circular preview
│       └── BottomNavigation.qml / BottomNavTab.qml / ConnectionStatus.qml
├── requirements.txt
└── README.md

Usage

Navigation

  • Bottom tabs switch between the five pages:
    • Browse: search and pick patterns
    • Playlists: create and run playlists
    • Control: connection, movement, and device settings
    • Light: the table's LED ring
    • Now Playing: live progress ring and transport controls

Pattern Management

  1. Browse Patterns: Swipe to Patterns page to see grid view with thumbnail previews
  2. Search: Use the search field to filter patterns by name
  3. Select Pattern: Tap a pattern card to view details and execution options
  4. Execute: Choose pre-execution action and tap "Play Pattern"

Table Control

  1. Monitor Status: Swipe to Control page to see current pattern and progress
  2. Control Execution: Use Pause/Resume and Stop buttons
  3. Quick Actions: Use Clear In, Clear Out, or Circle pattern shortcuts
  4. Connection Status: View WebSocket connection status

Notes

  • The touch interface talks directly to the table firmware; no host service is required
  • The firmware's HTTP API is multi-client, so the app can run alongside other clients (phone/web app, Home Assistant) at the same time
  • Pattern previews render locally the first time a pattern is seen, then load from cache
  • Requires the table to be reachable on the network (mDNS or DUNE_WEAVER_URL)