Browser-based app to automatically switch Spotify playlists based on cycling power output from a Bluetooth smart trainer.
- π΅ Automatic Spotify playlist switching based on power output
- π΄ Real-time power monitoring via Web Bluetooth
- β‘ FTP-based power to playlist mapping
- π¨ Modern, simple, responsive UI
- πΎ Local storage for configuration persistence
- Browser: Chrome or Edge (Web Bluetooth API required)
- Spotify: Premium account
- Device: Bluetooth smart trainer or power meter with Cycling Power Service
- Connection: HTTPS (or localhost for development)
- Go to Spotify Developer Dashboard
- Create a new app
- Add redirect URI:
http://localhost:5173/callback - Copy your Client ID
# Install dependencies
npm install
# Create environment file
cp .env.local.example .env.local
# Add your Spotify Client ID to .env.local
# VITE_SPOTIFY_CLIENT_ID=your_client_id_herenpm run devOpen http://localhost:5173 in Chrome or Edge.
- Login: Click "Login with Spotify" and authorize the app
- Configure FTP: Enter your Functional Threshold Power in watts
- Connect Device: Click "Scan" to select your smart trainer
- Power to Playlist: Define power thresholds (% of FTP) and assign playlists
- Save: Configuration is saved automatically
- Start Workout: Click "Start Workout" on the config page
- Connect: Allow Bluetooth permission when prompted
- Ride: The app will automatically switch playlists based on your power output
- Monitor: Watch real-time power, FTP %, and current playlist
| Min Power % | Playlist |
|---|---|
| 95% | Heavy Metal |
| 80% | Rock Classics |
| 60% | Instrumental Blues |
| 0% | Calm Acoustic |
When your power is at 85% FTP, it will play "Hard Efforts". When you push to 100% FTP, it switches to "Maximum Intensity".
- Vue 3 - Progressive JavaScript framework
- TypeScript - Type-safe JavaScript
- Vite - Fast build tool
- Tailwind CSS - Utility-first CSS framework
- Pinia - State management
- Vue Router - Client-side routing
- Spotify Web API - Music control
- Web Bluetooth API - Trainer connectivity
src/
βββ components/ # Reusable UI components
βββ views/ # Page components
β βββ LoginView.vue
β βββ CallbackView.vue
β βββ ConfigView.vue
β βββ WorkoutView.vue
β βββ SettingsView.vue
βββ services/ # API and Bluetooth services
β βββ spotify.ts
β βββ bluetooth.ts
βββ stores/ # Pinia state management
β βββ auth.ts
β βββ config.ts
β βββ playlists.ts
β βββ workout.ts
βββ router/ # Vue Router configuration
βββ types/ # TypeScript type definitions
- Make sure your device is powered on and in pairing mode
- Disconnect from other apps (Zwift, TrainerRoad, etc.)
- Try refreshing the page and scanning again
- Check that you're using Chrome or Edge
- Ensure Spotify is open on at least one device
- Check that you have an active Spotify Premium subscription
- Verify the app has playback permissions
- Verify your Client ID in
.env.local - Check that redirect URI matches in Spotify Developer Dashboard
- Try logging out and logging back in
# Run dev server
npm run dev
# Type checking
npm run type-check
# Build for production
npm run build
# Preview production build
npm run previewThe app can be deployed to any static hosting service:
- GitHub Pages: Free hosting for public repos
- Vercel: One-click deployment with automatic HTTPS
- Netlify: Similar to Vercel with easy setup
Important: Update the redirect URI in your Spotify Developer Dashboard to match your production URL.
- Browser Support: Chrome and Edge only (Web Bluetooth limitation)
- HTTPS Required: Must be served over HTTPS (except localhost)
- Active Spotify Session: Requires Spotify to be playing on a device
- Single Device: Bluetooth can only connect to one app at a time
- API Rate Limits: Spotify has rate limits on playlist switching
BSD-3-Clause
See LICENSE for details.