# 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. ```mermaid 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 `.exe` with 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.yaml` created 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 1. **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. 2. **External Scripts/CLI:** Cryptographic Bearer Token via `Authorization: Bearer ` 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) ```bash 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 ```bash 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: 1. **Environment variables:** - `DASHBOARD_PIN` — (optional, auto-generated if missing) - `API_TOKEN` — Bearer token for external scripts - `PIN_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) 2. **`.env` file** (in project root or exe directory): ``` API_TOKEN=your-token-here PIN_TTL=300 HOST=192.168.1.100 PORT=8921 LOG_LEVEL=INFO ``` 3. **`config.yaml`** (auto-created on first run, or manually): ```yaml 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 ```bash 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 ```bash 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. ```bash cd android ./gradlew assembleDebug # APK at: app/build/outputs/apk/debug/app-debug.apk ``` Install via ADB: ```bash 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://: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:** 1. Create a new values folder: `android/app/src/main/res/values-{lang}/` - Example: `values-es/` for Spanish, `values-fr/` for French 2. Copy `values/strings.xml` to the new folder 3. Translate the string values **Example `values-es/strings.xml`:** ```xml PaperDash PaperDash Ingrese PIN para conectar **** Conectar Ingrese un PIN Desconectado. Reingrese PIN. Conectando… Sin reproducción SILENCIAR SILENCIADO Sin notificaciones ETA: ``` 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](LICENSE) for details.