3.0 KiB
3.0 KiB
Mirror OS
Smart mirror app platform built with Flutter for a hacked Lululemon Mirror (BOE panel + Vizio driver board + Raspberry Pi 4).
Architecture
Melos mono-repo with two apps sharing packages:
apps/display— Flutter Linux desktop app, runs fullscreen on Pi 4 (1080x1920 portrait)apps/remote— Flutter mobile app (iOS/Android), phone remote controlpackages/mirror_protocol— WebSocket message types and serializationpackages/mirror_core— Shared business logic, API clients (workout-player, YouTube)packages/mirror_ui— Dark theme, shared widgets, animationsservices/— Python sidecars for voice (OpenWakeWord + Whisper) and motion (PIR/GPIO)deploy/— Pi setup scripts, systemd units, labwc compositor config
Prerequisites
- Flutter SDK 3.24+ (stable channel)
- Dart SDK 3.5+
- Melos:
dart pub global activate melos
Setup
melos bootstrap
Development
# Run display app (macOS/Linux desktop for development)
cd apps/display && flutter run -d macos
# Run remote app on iOS simulator
cd apps/remote && flutter run
# Run both and test WebSocket communication:
# 1. Start display app (starts WS server on :9090)
# 2. Start remote app, connect to localhost:9090
# Analyze all packages
melos run analyze
# Format all packages
melos run format
Hardware
- Panel: BOE DV430FHM-NN5, 43" 1080p IPS, portrait orientation (1080x1920)
- Driver board: Vizio mainboard (HDMI passthrough → LVDS → panel)
- Compute: Raspberry Pi 4 (4GB)
- Control: Phone over same WiFi network
- Rotation: Pi handles via
wlr-randr --output HDMI-A-1 --transform 90
Communication
Display app runs a WebSocket server on port 9090. Phone remote connects as a client.
Protocol: JSON messages, typed via sealed Dart classes in mirror_protocol package.
- Server → Client:
StateSync(full state on connect),StatePatch(deltas) - Client → Server:
NavigateCommand,PlaybackCommand,WorkoutCommand
External Services
- Workout Player: http://192.168.86.172:8091 — REST API for video library, streaming, progress
- OpenWeather: API key needed for dashboard weather widget
- Google Calendar: OAuth for dashboard calendar widget
- Plex: Local server on same LAN
Build for Pi 4
# On the Pi (with Flutter installed):
cd apps/display
flutter build linux --release
# Output: build/linux/arm64/release/bundle/
# Deploy: rsync bundle to /opt/mirror-os/display/ on the Pi
Testing
# Unit tests
melos exec -- dart test
# Integration: start display app, connect remote, verify state sync
Key Design Decisions
- Riverpod for state management (no code generation needed for basic use)
- Single
DisplayStateas source of truth on the Pi, broadcast to all remotes - media_kit (mpv) for media playback with V4L2 hardware decoding
- Python sidecars for voice/motion (communicate via Unix domain sockets)
- No touch input on mirror — all interaction via phone remote