- start.bat and start.sh now create conda env (paperdash, Python 3.11) - README updated with conda setup instructions - Fixes pyhwinfo installation issues on Python 3.12+
E-INK Dashboard Ecosystem ~ Paperdash
A local network dashboard ecosystem designed for the Onyx Boox Go 7 Color (Android E-Ink display). It displays real-time Windows desktop states including media playback, audio mixer channels (Windows default output or Voicemeeter), system telemetry, and custom script notifications (progress bars and rich text alerts).
Copyright (c) Imrayya (2026) — MIT License
Architecture
Paperdash bypasses heavyweight native Android UIs in favor of a lightweight, asynchronous Python server communicating via low-overhead WebSockets to a highly optimized E-Ink web client.
flowchart TD
subgraph WindowsHost["WINDOWS HOST PC"]
subgraph Subsystems["Subsystems"]
Media["WinRT Media API"]
Audio["Windows Audio / Core Audio"]
VM["Voicemeeter API"]
HW["HWiNFO Shared Memory"]
end
Server["FastAPI Server"]
StateAgg["State Aggregator"]
Auth["Token Auth Engine"]
end
subgraph External["EXTERNAL CLIENTS"]
Script["Custom Script / CLI"]
end
subgraph Boox["ONYX BOOX GO 7 COLOR (Android 13)"]
APK["Android WebView APK
(Kotlin)"]
style APK fill:#000,color:#fff
end
Media --> Server
Audio --> Server
VM --> Server
HW --> Server
Server --> StateAgg
Server --> Auth
Script -->|Bearer Token| Auth
StateAgg -->|WebSocket| WebView
Auth -->|PIN Auth| WebView
Client-side optimizations: PIN-authenticated WebSocket connection, static DOM updates (no smooth scrolling/fades), full-screen CSS Grid layout with static tap-and-swipe gestures.
Tech Stack
Server (Python 3.11+, Windows)
- FastAPI + Uvicorn — ASGI web framework with native async WebSocket handling
- winsdk — Windows Media API for GSMTC (Global System Media Transport Controls)
- pysounddevice / pycaw — Generic Windows Core Audio API for default output volume and mute
- voicemeeter-api — Voicemeeter Remote API wrapper for per-strip mixer controls
- pyhwinfo — Hardware telemetry via HWiNFO64 Shared Memory
- PyInstaller — Compiles the server to a standalone
.exewith system tray icon
Client (BOOX Go 7 Color, Android 13)
- Custom Android WebView APK — Kotlin app wrapping the web client in a full-screen WebView
- Vanilla JavaScript (ES6+) + CSS — configured for monochrome/high-contrast E-Ink palettes
Features
- Media Playback Tracking — Song title, artist, playback percentage, and cover art via Windows GSMTC
- Audio Mixer Control — Real-time volume and mute from Windows default output or Voicemeeter per-strip gains, mutes, and track states
- Hardware Telemetry — CPU/GPU core temps, VRAM usage from HWiNFO64
- Hardware Fallbacks — Startup check reports which subsystems are available/unavailable
- Custom Notifications — External scripts can push progress bars or rich text alerts via
POST /api/v1/notify - Settings Page — Localhost-only web UI at
/settings(accessed via tray icon) to edit PIN, token, host, port, log level, and PIN TTL - Secure PIN System — 6-digit codes with 5-minute TTL, single-use, auto-generated on startup
- Cryptographic API Token — 256-bit entropy via
secrets.token_urlsafe(32) - Auto-Configuration —
config.yamlcreated automatically on first run with detected local IP - Configuration Files — Use
config.yaml,.env, or environment variables - E-Ink Optimized UI — High-contrast styling, discrete zone gestures, minimal refresh
- System Tray .exe — Runs unobtrusively in the Windows notification bar with Settings and Quit options
Authentication
- Dashboard UI (Boox Tablet): Time-limited PIN authentication via WebSocket handshake (
?pin=XXXX). PINs are 6-digit, expire after 5 minutes (configurable), and can only be used once. - External Scripts/CLI: Cryptographic Bearer Token via
Authorization: Bearer <SECRET_TOKEN>header (32 bytes / 256 bits of entropy)
Project Structure
e-ink-dash/
├── .pi/
│ ├── docs/design/ # Design decision records
│ └── paperdash_architecture_document.txt
├── server/ # Python FastAPI server
│ ├── main.py # Application entry point
│ ├── config.py # Configuration management (YAML/.env/env vars)
│ ├── pin_manager.py # Time-limited single-use PIN generation
│ ├── audio_mixer.py # Audio mixer abstraction (Windows + Voicemeeter)
│ ├── media.py # Media playback tracking (GSMTC)
│ ├── notifications.py # Notification system (progress + alerts)
│ ├── telemetry.py # Hardware telemetry (HWiNFO)
│ ├── tray_wrapper.py # System tray .exe wrapper
│ ├── settings.html # Settings page (localhost-only)
│ ├── settings.css # Settings page stylesheet
│ ├── build_exe.py # PyInstaller build script
│ ├── start.bat # Windows development startup
│ ├── start.sh # Linux/macOS development startup
│ ├── .env.example # Example environment file
│ ├── requirements.txt
│ └── tests/ # Test suite
├── client/ # E-Ink web client
│ ├── index.html
│ ├── style.css
│ └── app.js
├── README.md
├── LICENSE
└── .gitignore
Getting Started
Quick Start (Development)
cd server
bash start.bat # Windows
# or
bash start.sh # Linux/macOS
The scripts create a conda env (paperdash with Python 3.11), install dependencies, and start the server. On first run, config.yaml is auto-generated with:
- A random 6-digit PIN (logged to console)
- A random API token (logged to console)
- Detected local IP address
- Default port 8921
Manual Setup
cd server
conda create -y -n paperdash python=3.11
conda activate paperdash
pip install -r requirements.txt
python -m uvicorn main:app --host 0.0.0.0 --port 8921
Configure via one of:
-
Environment variables:
DASHBOARD_PIN— (optional, auto-generated if missing)API_TOKEN— Bearer token for external scriptsPIN_TTL— PIN expiration in seconds (default: 300)HOST— Server bind address (default: detected local IP)PORT— Server port (default: 8921)LOG_LEVEL— Logging level (default: INFO)
-
.envfile (in project root or exe directory):API_TOKEN=your-token-here PIN_TTL=300 HOST=192.168.1.100 PORT=8921 LOG_LEVEL=INFO -
config.yaml(auto-created on first run, or manually):api_token: "your-token-here" pin_ttl: 300 host: "192.168.1.100" port: 8921 log_level: "INFO"
Settings Page
Access the settings UI via the system tray icon → Settings. This opens http://127.0.0.1:8921/settings in your browser.
Available only from localhost — you must be on the PC running PaperDash.
Edit: PIN, API token, host, port, log level, and PIN TTL. Changes are saved to config.yaml and take effect on next restart.
Build .exe
cd server
python build_exe.py
# Output: server/dist/PaperDash.exe
The .exe bundles settings.html and settings.css for the settings page.
Build .exe
cd server
python build_exe.py
# Output: server/dist/PaperDash.exe
Client (Android APK)
The web client is bundled into an Android APK. Open Android Studio, sync Gradle, and run on the BOOX Go 7 Color.
cd android
./gradlew assembleDebug
# APK at: app/build/outputs/apk/debug/app-debug.apk
Install via ADB:
adb install app/build/outputs/apk/debug/app-debug.apk
The WebView loads file:///android_asset/index.html and connects to the server via WebSocket at ws://<pc-ip>:8921/ws.
Localization
The app supports multiple languages via Android string resources. The web client loads strings from Android via a JavaScript interface.
Adding a new language:
- Create a new values folder:
android/app/src/main/res/values-{lang}/- Example:
values-es/for Spanish,values-fr/for French
- Example:
- Copy
values/strings.xmlto the new folder - Translate the string values
Example values-es/strings.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">PaperDash</string>
<string name="login_title">PaperDash</string>
<string name="login_subtitle">Ingrese PIN para conectar</string>
<string name="login_placeholder">****</string>
<string name="login_button">Conectar</string>
<string name="login_error_enter_pin">Ingrese un PIN</string>
<string name="login_error_disconnected">Desconectado. Reingrese PIN.</string>
<string name="connecting">Conectando…</string>
<string name="no_playback">Sin reproducción</string>
<string name="mute">SILENCIAR</string>
<string name="muted">SILENCIADO</string>
<string name="no_notifications">Sin notificaciones</string>
<string name="eta_prefix">ETA:</string>
</resources>
The app automatically uses the device's language. No code changes needed.
Design Decisions
See .pi/docs/design/ for detailed design decision records covering architecture, audio mixer, notifications, and the .exe build.
License
MIT — see LICENSE for details.