mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 08:36:13 +00:00
## New Endpoints ### GET /name ✅ - Simple device name retrieval with XML parsing - Helper methods for name validation and display - Real device name integration with anonymization ### GET /capabilities ✅ - Comprehensive device capabilities detection - Complex XML structure with nested network, DSP, and system configurations - Smart categorization: System Features, Audio Features, Network Features - Capability-specific helper methods (HasLRStereoCapability, HasDualModeNetwork, etc.) - Extended capabilities parsing with URLs and metadata ### GET /presets ✅ - Complete preset management with timestamps and metadata - Spotify playlist integration with anonymized account information - Smart filtering: by source, used/empty slots, most recent, oldest presets - Comprehensive analysis: preset summaries with source breakdowns - Time-based operations: creation/update timestamps with formatted display ## Device Introspection Features ### Capability Detection - System capabilities: Light Switch, Clock Display, BCO Reset, Power Saving - Audio capabilities: L/R Stereo support, DSP Mono/Stereo availability - Network capabilities: Dual Mode, WSAPI Proxy, Hosted WiFi Configuration - Extended capabilities: Custom endpoint discovery with URL mapping ### Preset Analysis - Usage pattern analysis (used vs empty slots) - Source distribution (Spotify, TuneIn, etc.) - Temporal analysis (most recent, oldest presets) - Content metadata extraction (artwork URLs, display names) ## Enhanced CLI Tool ### New Commands - Added -name command with simple device identification - Added -capabilities command with categorized feature display - Added -presets command with comprehensive preset analysis - Enhanced help system with all new command examples ### Rich Output Formatting - Capability categorization with bullet-point display - Preset timeline with creation/update timestamps - Smart metadata display (artwork, source accounts, content types) - Device-specific feature highlighting (different capabilities per device) ## Real Device Integration ### Multi-Device Testing - Device 192.168.178.28: SoundTouch 10 with Light Switch, Clock Display, Hosted WiFi - Device 192.168.178.35: SoundTouch 20 with L/R Stereo, Dual Mode networking - Verified capability differences between device models - Real preset data with anonymized Spotify account information ### Edge Case Handling - Non-responsive endpoints (/trackInfo timeout handling) - Empty preset configurations - Missing capability sections - Device-specific feature variations ## Quality & Testing ### Comprehensive Test Coverage - 15+ unit tests for XML models with real device response patterns - Client integration tests with mock HTTP servers - Edge case validation (empty names, missing capabilities, no presets) - Timestamp parsing and validation with Unix epoch conversion ### Production-Ready Features - Type-safe XML unmarshaling with custom validation - Robust error handling for network and parsing failures - Privacy protection with anonymized real device data - Documentation updates with real-world usage examples ## API Coverage Progress ✅ Complete Information Endpoints: - GET /info - Device information - GET /name - Device name - GET /capabilities - Device capabilities - GET /presets - Configured presets - GET /now_playing - Current playback status - GET /sources - Available audio sources 🔄 Next Phase - Control Endpoints: - POST /key - Media controls - GET/POST /volume - Volume management - WebSocket / - Real-time events Features: ✅ Comprehensive device introspection and capability detection ✅ Smart preset management with timeline analysis ✅ Multi-device support with hardware-specific feature detection ✅ Production-ready error handling and data validation ✅ Rich CLI interface with categorized output formatting ✅ Real device integration with privacy-protected test data
22 KiB
22 KiB
Bose SoundTouch API Client - Golang Implementation Plan
Overview
This document describes the planning for a Golang-based API client for the Bose SoundTouch Web API. The client follows modern Go patterns and supports both native Go library and WASM integration with embedded web UI.
New insights from pattern analysis:
- Single binary deployment with embedded assets
- Multi-target build system (Native + WASM)
- CORS proxy pattern for browser integration
- Robust XML API client patterns
- Production-ready configuration management
API Fundamentals
Basic Information
- Protocol: HTTP REST-like
- Data format: XML Request/Response
- Port: 8090 (default)
- Authentication: No complex authentication required
- Real-time updates: WebSocket connection available
- Device discovery: UPnP discovery possible
Core API Endpoints
GET /info- Device informationGET /now_playing- Currently playing musicPOST /key- Send key commands (PLAY, PAUSE, etc.)GET/POST /volume- Control volumeGET/POST /bass- Bass settingsGET/POST /sources- Available sourcesPOST /select- Select sourceGET/POST /presets- Manage presets (1-6)WebSocket /- Live updates for events
Architecture Based on Modern Go Patterns
Final Project Structure
github.com/user_account/bose-soundtouch/
├── cmd/
│ ├── cli/ # CLI Tool (Main Application)
│ │ └── main.go
│ ├── webapp/ # Web Application with embedded Assets
│ │ ├── main.go
│ │ └── web/ # Embedded HTML/CSS/JS
│ │ ├── index.html
│ │ ├── app.js
│ │ └── style.css
│ └── wasm/ # WASM Entry Point
│ └── main.go
├── pkg/ # Public API (external usage)
│ ├── client/ # HTTP Client with XML Support
│ ├── discovery/ # UPnP Device Discovery
│ ├── models/ # Type-safe XML Data Models
│ ├── websocket/ # Event Streaming Client
│ ├── wasm/ # WASM JavaScript Bridge
│ └── config/ # Configuration Management
├── internal/ # Private Implementation Details
│ ├── xml/ # XML Parsing Utilities
│ ├── http/ # HTTP Utilities & Middleware
│ └── testing/ # Mock Client & Test Utilities
├── web/ # Frontend Development Assets
│ ├── src/ # Source files
│ └── dist/ # Build output → cmd/webapp/web/
├── examples/ # Usage Examples & Demos
├── test/ # Integration Tests & Docker
├── Makefile # Comprehensive Build System
├── .env.example # Configuration Template
├── .air-webapp.toml # Hot Reload Config
├── .air-wasm.toml # WASM Development Config
├── docker-compose.yml # Development Environment
├── PROJECT-PATTERNS.md # Pattern Documentation
├── API-Endpoints-Overview.md # API Reference
├── go.mod
└── README.md
Core Components (Updated)
1. HTTP Client with XML Support (pkg/client)
type Client struct {
baseURL string
httpClient *http.Client
timeout time.Duration
userAgent string
}
type ClientConfig struct {
Host string
Port int
Timeout time.Duration
UserAgent string
}
// Core API methods
func NewClient(config ClientConfig) *Client
func (c *Client) GetDeviceInfo() (*models.DeviceInfo, error)
func (c *Client) GetNowPlaying() (*models.NowPlaying, error)
func (c *Client) SetVolume(volume int) error
func (c *Client) GetVolume() (*models.Volume, error)
func (c *Client) SendKey(key models.Key) error
func (c *Client) GetSources() (*models.Sources, error)
func (c *Client) SelectSource(source models.ContentItem) error
func (c *Client) GetPresets() (*models.Presets, error)
func (c *Client) SetPreset(id int, content models.ContentItem) error
// HTTP utilities with XML handling
func (c *Client) get(endpoint string, result interface{}) error
func (c *Client) post(endpoint string, data interface{}, result interface{}) error
2. UPnP Device Discovery (pkg/discovery)
type DiscoveryService struct {
timeout time.Duration
cache map[string]*Device
cacheTTL time.Duration
mutex sync.RWMutex
}
type Device struct {
Name string `json:"name"`
Host string `json:"host"`
Port int `json:"port"`
ModelID string `json:"modelId"`
SerialNo string `json:"serialNo"`
Location string `json:"location"`
LastSeen time.Time `json:"lastSeen"`
}
func NewDiscoveryService(timeout time.Duration) *DiscoveryService
func (d *DiscoveryService) DiscoverDevices() ([]Device, error)
func (d *DiscoveryService) DiscoverDevice(name string) (*Device, error)
func (d *DiscoveryService) GetCachedDevices() []Device
func (d *DiscoveryService) ClearCache()
// SSDP/UPnP implementation
func (d *DiscoveryService) sendMSearch() error
func (d *DiscoveryService) parseResponse(response string) (*Device, error)
3. Typsichere XML Models (pkg/models)
// Base XML response with error handling
type XMLResponse struct {
XMLName xml.Name `xml:",innerxml"`
Error *APIError `xml:"error,omitempty"`
}
type APIError struct {
Code string `xml:"code,attr"`
Message string `xml:",innerxml"`
}
// Device Info
type DeviceInfo struct {
XMLResponse
XMLName xml.Name `xml:"info"`
DeviceID string `xml:"deviceID,attr"`
Name string `xml:"name"`
Type string `xml:"type"`
Components []string `xml:"components>component"`
// ... additional fields
}
// Now Playing with complete structure
type NowPlaying struct {
XMLResponse
XMLName xml.Name `xml:"nowPlaying"`
DeviceID string `xml:"deviceID,attr"`
Source string `xml:"source,attr"`
Content ContentItem `xml:"ContentItem"`
Track string `xml:"track"`
Artist string `xml:"artist"`
Album string `xml:"album"`
Art Art `xml:"art"`
PlayStatus PlayStatus `xml:"playStatus"`
Position Position `xml:"position,omitempty"`
}
// Enum types with validation
type PlayStatus string
const (
PlayStatusPlaying PlayStatus = "PLAY_STATE"
PlayStatusPaused PlayStatus = "PAUSE_STATE"
PlayStatusStopped PlayStatus = "STOP_STATE"
)
type Key string
const (
KeyPlay Key = "PLAY"
KeyPause Key = "PAUSE"
KeyStop Key = "STOP"
KeyPrevTrack Key = "PREV_TRACK"
KeyNextTrack Key = "NEXT_TRACK"
KeyVolumeUp Key = "VOLUME_UP"
KeyVolumeDown Key = "VOLUME_DOWN"
KeyMute Key = "MUTE"
KeyPower Key = "POWER"
KeyPreset1 Key = "PRESET_1"
KeyPreset2 Key = "PRESET_2"
KeyPreset3 Key = "PRESET_3"
KeyPreset4 Key = "PRESET_4"
KeyPreset5 Key = "PRESET_5"
KeyPreset6 Key = "PRESET_6"
)
4. WebSocket Event Client (pkg/websocket)
type EventClient struct {
client *client.Client
conn *websocket.Conn
handlers map[string]EventHandler
stopChan chan bool
reconnect bool
backoff time.Duration
maxBackoff time.Duration
}
type EventHandler func(event Event)
type Event struct {
Type string `xml:"type,attr"`
DeviceID string `xml:"deviceID,attr"`
Data interface{} `xml:",innerxml"`
Timestamp time.Time `json:"timestamp"`
}
func NewEventClient(client *client.Client) *EventClient
func (e *EventClient) Subscribe(eventType string, handler EventHandler)
func (e *EventClient) Unsubscribe(eventType string)
func (e *EventClient) Start() error
func (e *EventClient) Stop() error
func (e *EventClient) IsConnected() bool
// Event types
const (
EventNowPlayingUpdated = "nowPlayingUpdated"
EventVolumeUpdated = "volumeUpdated"
EventConnectionState = "connectionStateUpdated"
EventPresetUpdated = "presetUpdated"
)
5. WASM JavaScript Bridge (pkg/wasm)
//go:build wasm
// +build wasm
import "syscall/js"
// Global WASM API registration
func RegisterWASMFunctions()
// Device Discovery (via proxy)
func wasmDiscoverDevices(this js.Value, args []js.Value) interface{}
// Client Management
func wasmCreateClient(this js.Value, args []js.Value) interface{}
func wasmGetNowPlaying(this js.Value, args []js.Value) interface{}
func wasmSendKey(this js.Value, args []js.Value) interface{}
func wasmSetVolume(this js.Value, args []js.Value) interface{}
func wasmGetSources(this js.Value, args []js.Value) interface{}
// Event Streaming
func wasmStartEventStream(this js.Value, args []js.Value) interface{}
func wasmStopEventStream(this js.Value, args []js.Value) interface{}
6. Configuration Management (pkg/config)
type Config struct {
// Server configuration
WebPort int `env:"WEB_PORT" default:"8080"`
APITimeout time.Duration `env:"API_TIMEOUT" default:"10s"`
// Discovery configuration
DiscoveryTimeout time.Duration `env:"DISCOVERY_TIMEOUT" default:"5s"`
CacheDevices bool `env:"CACHE_DEVICES" default:"true"`
CacheTTL time.Duration `env:"CACHE_TTL" default:"5m"`
// CORS configuration (for web proxy)
CORSOrigins []string `env:"CORS_ORIGINS" default:"*"`
// Logging
LogLevel string `env:"LOG_LEVEL" default:"info"`
LogFormat string `env:"LOG_FORMAT" default:"json"`
// Development
DevMode bool `env:"DEV_MODE" default:"false"`
}
func Load() Config
func LoadFromFile(filename string) (Config, error)
func (c Config) Validate() error
Implementation Roadmap (Updated)
Phase 1: Foundation & Core API ⭐ (Priority)
- Go module setup with modern dependencies
- HTTP Client with XML Support ✅ DONE
- Basic client structure
- GET/POST methods with XML marshaling
- Error handling for HTTP + XML
- Timeout and retry logic
- Core XML models ✅ DONE
- DeviceInfo - Device information endpoint
- NowPlaying - Current playback status endpoint
- Sources - Available audio sources endpoint
- Name - Device name endpoint
- Capabilities - Device capabilities endpoint
- Presets - Configured presets endpoint
- Custom XML unmarshaling for enums
- Validation and defaults
- CLI tool for testing ✅ DONE
- Test device connection
- Device discovery via UPnP
- Device info retrieval
- Now playing status
- Audio sources listing
- Device name retrieval
- Device capabilities inspection
- Preset configuration listing
- Unit tests with mocks ✅ DONE
- HTTP client tests
- XML parsing tests
- Mock responses with real device data
Phase 2: Device Discovery & Management 🔍
- Implement UPnP SSDP Discovery
- M-SEARCH implementation
- Response parsing
- Device caching with TTL
- CLI Device Selection
- Automatic discovery
- Interactive device selection
- Saved device configuration
- Integration Tests
- Tests against real SoundTouch devices
- Docker-based mock devices
- Error Handling & Logging
- Structured logging
- Graceful error handling
- Network error recovery
Phase 3: WebSocket Real-time Events 📡
- Implement WebSocket Client
- Connection Management
- Event parsing and routing
- Reconnection with exponential backoff
- Event Handler System
- Typed event structs
- Handler Registration
- Event Filtering
- CLI Real-time Monitoring
- Live Now-Playing Updates
- Volume Change Monitoring
- Connection Status Display
- Event Storage & History
- Event logging for debugging
- Historical Event Queries
Phase 4: Web Application & CORS Proxy 🌐
- Create Embedded Web UI
- HTML/CSS/JS for SoundTouch control
- Responsive design for mobile
- Real-time Updates via WebSocket
- CORS-Proxy Server
- HTTP proxy to local SoundTouch devices
- WebSocket proxy for events
- CORS Header Management
- Single Binary with Embedded Assets
- go:embed for web assets
- Static File Serving
- SPA Routing Support
- Web-UI Features
- Device Discovery & Selection
- Now playing display with album art
- Volume & Bass Controls
- Source Selection
- Preset Management
Phase 5: WASM Browser Integration 🧩
- WASM Build Configuration
- Build tags and conditional compilation
- WASM-specific HTTP client (via proxy)
- JavaScript Promise Integration
- WASM JavaScript Bridge
- Go function export to JavaScript
- Asynchronous API calls
- Error handling via promise rejection
- Browser Demo Application
- Pure Frontend SoundTouch Control
- Local Network Device Discovery (via Proxy)
- Real-time Event Updates
- Cross-Origin Solutions
- Local proxy server for development
- Browser Extension Support
- Documentation for CORS issues
Phase 6: Production Features & Polish 🚀
- Advanced Configuration
- Environment-based Config
- Configuration File Support
- Runtime Configuration Updates
- Multi-Device Support
- Multiple Device Connections
- Device Groups/Zones
- Synchronized Operations
- Preset & Source Management
- Preset Backup/Restore
- Custom Source Integration
- Playlist Management
- Performance Optimizations
- Connection Pooling
- Request Caching
- Lazy Loading
- Documentation & Examples
- Comprehensive API Documentation
- Usage examples for all use cases
- Best Practices Guide
Build System Based on Modern Patterns
Makefile with Multi-Target Support
BINARY_NAME=soundtouch
VERSION?=$(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
BUILD_TIME=$(shell date -u '+%Y-%m-%d_%H:%M:%S')
GO_VERSION=$(shell go version | cut -d ' ' -f 3)
LDFLAGS=-ldflags "-X main.Version=$(VERSION) -X main.BuildTime=$(BUILD_TIME) -X main.GoVersion=$(GO_VERSION)"
BUILD_FLAGS=-trimpath $(LDFLAGS)
# Development builds
build:
go build $(BUILD_FLAGS) -o $(BINARY_NAME) ./cmd/cli
build-webapp:
go build $(BUILD_FLAGS) -o $(BINARY_NAME)-webapp ./cmd/webapp
# WASM build
build-wasm:
GOOS=js GOARCH=wasm go build $(BUILD_FLAGS) -o web/soundtouch.wasm ./cmd/wasm
cp "$(shell go env GOROOT)/misc/wasm/wasm_exec.js" web/
# Cross-platform builds
build-all: build-linux build-darwin build-windows
# Development with hot reload
dev-cli:
air -c .air-cli.toml
dev-webapp:
air -c .air-webapp.toml
dev-wasm:
air -c .air-wasm.toml
# Testing
test:
go test -v -race ./...
test-coverage:
go test -v -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
# Quality checks
check: fmt vet lint test
# Docker development environment
docker-dev:
docker-compose up --build
# Release packaging
release: build-all
mkdir -p dist
tar -czf dist/$(BINARY_NAME)-$(VERSION)-linux-amd64.tar.gz $(BINARY_NAME)-linux-amd64
tar -czf dist/$(BINARY_NAME)-$(VERSION)-darwin-amd64.tar.gz $(BINARY_NAME)-darwin-amd64
zip dist/$(BINARY_NAME)-$(VERSION)-windows-amd64.zip $(BINARY_NAME)-windows-amd64.exe
Technical Solution Approaches (Updated)
WASM Browser Integration
- CORS Proxy Pattern: Go web app as proxy between browser and SoundTouch devices
- Local Development Server: CORS headers for local development
- WebSocket Proxy: Real-time events via secure WebSocket connection
- Graceful Degradation: Functionality depending on browser environment
XML API Robustness
- Type-Safe Models: Strict Go structs with validation
- Custom Unmarshaling: Enum validation and error recovery
- Timeout Handling: Robust network calls with retry logic
- Connection Pooling: Efficient HTTP client reuse
Multi-Platform Deployment
- Single Binary: Embedded assets eliminate external dependencies
- Cross-Compilation: Native binaries for all platforms
- Docker Support: Containerized development and deployment
- Progressive Enhancement: CLI → WebApp → WASM depending on requirements
Example Usage (Updated)
Native Go Library
package main
import (
"fmt"
"log"
"time"
"github.com/user_account/bose-soundtouch/pkg/client"
"github.com/user_account/bose-soundtouch/pkg/discovery"
"github.com/user_account/bose-soundtouch/pkg/models"
)
func main() {
// Discover devices
discoveryService := discovery.NewDiscoveryService(5 * time.Second)
devices, err := discoveryService.DiscoverDevices()
if err != nil {
log.Fatal(err)
}
if len(devices) == 0 {
log.Fatal("No SoundTouch devices found")
}
// Create client for first device
client := client.NewClient(client.ClientConfig{
Host: devices[0].Host,
Port: 8090,
Timeout: 10 * time.Second,
})
// Get device info
info, err := client.GetDeviceInfo()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Connected to: %s\n", info.Name)
// Get current playback
nowPlaying, err := client.GetNowPlaying()
if err != nil {
log.Fatal(err)
}
if nowPlaying.PlayStatus == models.PlayStatusPlaying {
fmt.Printf("Playing: %s - %s (%s)\n",
nowPlaying.Artist, nowPlaying.Track, nowPlaying.Album)
}
// Control playback
if nowPlaying.PlayStatus == models.PlayStatusPlaying {
client.SendKey(models.KeyPause)
fmt.Println("Paused playback")
} else {
client.SendKey(models.KeyPlay)
fmt.Println("Started playback")
}
}
CLI Usage
# Discover devices
soundtouch discover
# Device operations
soundtouch --device 192.168.1.100 info
soundtouch --device 192.168.1.100 play
soundtouch --device 192.168.1.100 volume 50
soundtouch --device 192.168.1.100 preset 1
# Interactive mode
soundtouch interactive
# Web interface
soundtouch-webapp --port 8080
JavaScript/WASM Usage
// Load WASM module
await loadWASM('/soundtouch.wasm');
// Discover devices (via proxy)
const devices = await boseAPI.discoverDevices();
console.log('Found devices:', devices);
// Create client
const client = boseAPI.createClient(devices[0].host, 8090);
// Get now playing
const nowPlaying = await client.getNowPlaying();
console.log(`Playing: ${nowPlaying.artist} - ${nowPlaying.track}`);
// Control playback
await client.sendKey('PAUSE');
// Volume control
await client.setVolume(75);
// Real-time events
client.startEventStream((event) => {
if (event.type === 'nowPlayingUpdated') {
updateUI(event.data);
}
});
Testing Strategy (Enhanced)
Unit Tests
- Mock HTTP Client: Simulierte SoundTouch-Responses
- XML Parsing Tests: Robustness für verschiedene Response-Formate
- Model Validation: Enum-Validation und Edge-Cases
- Error Handling: Network Failures und API Errors
Integration Tests
- Real Device Tests: Gegen echte SoundTouch-Hardware
- Docker Mock Server: Simulierte SoundTouch-API für CI/CD
- Discovery Tests: UPnP SSDP in verschiedenen Netzwerk-Szenarien
- WebSocket Tests: Event-Streaming und Reconnection
E2E Tests
- CLI Tests: Command-Line Interface Validation
- Web Interface Tests: Browser-basierte Tests mit Headless Chrome
- WASM Tests: Browser WASM Module Loading und Execution
- Cross-Platform Tests: Builds auf Linux/macOS/Windows
Deployment Strategies
Single Binary Distribution
# CLI Tool
./soundtouch-linux-amd64 discover
./soundtouch-linux-amd64 --device IP play
# Web Application (embedded assets)
./soundtouch-webapp-linux-amd64 --port 8080
# Docker
docker run -p 8080:8080 soundtouch-webapp
Development Environment
# Local development with hot reload
make dev-webapp # Web app development
make dev-wasm # WASM development
make dev-cli # CLI development
# Full development environment
docker-compose up # Mock devices + web app
Success Criteria
Phase 1-2 (Foundation)
- ✅ Stable HTTP API connection to SoundTouch devices
- ✅ XML model coverage for implemented APIs (DeviceInfo, NowPlaying, Sources, Name, Capabilities, Presets)
- ✅ Automatic device discovery via UPnP
- ✅ Functional CLI tool with discovery, info, now playing, sources, name, capabilities, and presets commands
- ✅ Now Playing endpoint with comprehensive status information
- ✅ Sources endpoint with filtering and categorization features
- ✅ Device identification endpoints (name, capabilities)
- ✅ Preset management with comprehensive analysis and filtering
Phase 3-4 (Real-time & Web)
- ✅ WebSocket event streaming with reconnection
- ✅ Web UI with responsive design
- ✅ Single binary deployment with embedded assets
- ✅ CORS proxy for browser integration
Phase 5-6 (Advanced)
- ✅ WASM integration with JavaScript bridge
- ✅ Multi-Device Support
- ✅ Production-ready Configuration Management
- ✅ Comprehensive documentation and examples
Resources & References
- Bose SoundTouch Web API Documentation
- Go WebAssembly
- UPnP Device Architecture
- Go Embed Directive
- Gorilla WebSocket
- PROJECT-PATTERNS.md - Detailed pattern documentation