mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-19 00:56:16 +00:00
docs: enhance pkg.go.dev documentation with comprehensive examples
- Add root package documentation with quick start guide and feature overview - Enhance client package with detailed usage examples and API coverage - Add comprehensive discovery package documentation with protocol explanations - Create models package documentation explaining all data structures - Add extensive example functions for all major use cases: * Basic device control and playback * Volume, bass, and balance management * Source selection and preset handling * Multiroom zone management * Real-time WebSocket event monitoring * Device discovery with UPnP and mDNS * Error handling and context cancellation - Include code examples for pkg.go.dev's example rendering - Document API endpoints, data structures, and best practices - Add hardware compatibility and implementation notes
This commit is contained in:
+141
-1
@@ -1,4 +1,144 @@
|
||||
// Package client provides HTTP client functionality for interacting with Bose SoundTouch devices.
|
||||
// Package client provides a comprehensive HTTP client for controlling Bose SoundTouch devices.
|
||||
//
|
||||
// This package implements the complete Bose SoundTouch Web API, enabling full programmatic
|
||||
// control of SoundTouch speakers including playback control, volume management, source
|
||||
// selection, multiroom zone management, and real-time event monitoring.
|
||||
//
|
||||
// # Basic Usage
|
||||
//
|
||||
// Create a client and control your SoundTouch device:
|
||||
//
|
||||
// config := &client.Config{
|
||||
// Host: "192.168.1.100",
|
||||
// Port: 8090,
|
||||
// Timeout: 10 * time.Second,
|
||||
// }
|
||||
// client := client.NewClient(config)
|
||||
//
|
||||
// // Get device information
|
||||
// info, err := client.GetInfo()
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// fmt.Printf("Device: %s (Type: %s)\n", info.Name, info.Type)
|
||||
//
|
||||
// // Control playback
|
||||
// err = client.Play()
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//
|
||||
// // Adjust volume
|
||||
// err = client.SetVolume(50)
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//
|
||||
// # Advanced Features
|
||||
//
|
||||
// The client supports all SoundTouch API endpoints:
|
||||
//
|
||||
// // Get current playback status
|
||||
// nowPlaying, err := client.GetNowPlaying()
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// fmt.Printf("Now Playing: %s by %s\n", nowPlaying.Track, nowPlaying.Artist)
|
||||
//
|
||||
// // Select audio source
|
||||
// err = client.SelectSource("SPOTIFY", "")
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//
|
||||
// // Control bass and balance
|
||||
// err = client.SetBass(3) // Range: -9 to +9
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//
|
||||
// err = client.SetBalance(-10) // Range: -50 (left) to +50 (right)
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//
|
||||
// # Multiroom Zone Management
|
||||
//
|
||||
// Create and manage multiroom zones:
|
||||
//
|
||||
// // Get current zone configuration
|
||||
// zone, err := client.GetZone()
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//
|
||||
// // Create a new zone with multiple speakers
|
||||
// newZone := &models.Zone{
|
||||
// Master: "192.168.1.100",
|
||||
// Members: []models.ZoneMember{
|
||||
// {IPAddress: "192.168.1.101"},
|
||||
// {IPAddress: "192.168.1.102"},
|
||||
// },
|
||||
// }
|
||||
// err = client.SetZone(newZone)
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//
|
||||
// # Real-time Events
|
||||
//
|
||||
// Monitor device state changes using WebSocket connections:
|
||||
//
|
||||
// ctx := context.Background()
|
||||
// events, err := client.SubscribeToEvents(ctx)
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//
|
||||
// for event := range events {
|
||||
// switch e := event.(type) {
|
||||
// case *models.NowPlayingUpdated:
|
||||
// fmt.Printf("Track changed: %s\n", e.Track)
|
||||
// case *models.VolumeUpdated:
|
||||
// fmt.Printf("Volume: %d\n", e.ActualVolume)
|
||||
// case *models.ConnectionStateUpdated:
|
||||
// fmt.Printf("Connection: %s\n", e.State)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// # Error Handling
|
||||
//
|
||||
// The client provides detailed error information:
|
||||
//
|
||||
// err := client.SetVolume(150) // Invalid volume
|
||||
// if err != nil {
|
||||
// fmt.Printf("Error: %v\n", err) // Will indicate volume out of range
|
||||
// }
|
||||
//
|
||||
// # Configuration
|
||||
//
|
||||
// The Config struct supports various options:
|
||||
//
|
||||
// config := &client.Config{
|
||||
// Host: "192.168.1.100",
|
||||
// Port: 8090,
|
||||
// Timeout: 15 * time.Second,
|
||||
// UserAgent: "MyApp/1.0",
|
||||
// }
|
||||
//
|
||||
// # Supported Operations
|
||||
//
|
||||
// - Device Information & Capabilities
|
||||
// - Playback Control (Play/Pause/Stop/Next/Previous/Key commands)
|
||||
// - Volume Control (Get/Set/Increment/Decrement)
|
||||
// - Bass Control (-9 to +9 range)
|
||||
// - Balance Control (-50 to +50 range)
|
||||
// - Source Selection (Spotify, Bluetooth, AUX, Radio, etc.)
|
||||
// - Preset Management (Get configured presets)
|
||||
// - Clock/Time Management
|
||||
// - Network Information
|
||||
// - Multiroom Zone Management
|
||||
// - Real-time WebSocket Event Monitoring
|
||||
package client
|
||||
|
||||
import (
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
package client_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/gesellix/bose-soundtouch/pkg/client"
|
||||
"github.com/gesellix/bose-soundtouch/pkg/models"
|
||||
)
|
||||
|
||||
// Example demonstrates basic device control operations.
|
||||
func Example() {
|
||||
// Create a client for your SoundTouch device
|
||||
config := &client.Config{
|
||||
Host: "192.168.1.100",
|
||||
Port: 8090,
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
c := client.NewClient(config)
|
||||
|
||||
// Get device information
|
||||
info, err := c.GetInfo()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("Device: %s\n", info.Name)
|
||||
|
||||
// Control playback
|
||||
err = c.Play()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Set volume to 50%
|
||||
err = c.SetVolume(50)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Device: Living Room Speaker
|
||||
}
|
||||
|
||||
// ExampleClient_GetNowPlaying demonstrates how to get current playback information.
|
||||
func ExampleClient_GetNowPlaying() {
|
||||
config := &client.Config{Host: "192.168.1.100"}
|
||||
c := client.NewClient(config)
|
||||
|
||||
nowPlaying, err := c.GetNowPlaying()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Track: %s\n", nowPlaying.Track)
|
||||
fmt.Printf("Artist: %s\n", nowPlaying.Artist)
|
||||
fmt.Printf("Album: %s\n", nowPlaying.Album)
|
||||
fmt.Printf("Source: %s\n", nowPlaying.Source)
|
||||
|
||||
// Output:
|
||||
// Track: Bohemian Rhapsody
|
||||
// Artist: Queen
|
||||
// Album: A Night at the Opera
|
||||
// Source: SPOTIFY
|
||||
}
|
||||
|
||||
// ExampleClient_SetVolume demonstrates volume control with validation.
|
||||
func ExampleClient_SetVolume() {
|
||||
config := &client.Config{Host: "192.168.1.100"}
|
||||
c := client.NewClient(config)
|
||||
|
||||
// Set volume to 75%
|
||||
err := c.SetVolume(75)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Get current volume
|
||||
volume, err := c.GetVolume()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Volume: %d\n", volume.ActualVolume)
|
||||
fmt.Printf("Muted: %t\n", volume.Muted)
|
||||
|
||||
// Output:
|
||||
// Volume: 75
|
||||
// Muted: false
|
||||
}
|
||||
|
||||
// ExampleClient_SelectSource demonstrates how to change audio sources.
|
||||
func ExampleClient_SelectSource() {
|
||||
config := &client.Config{Host: "192.168.1.100"}
|
||||
c := client.NewClient(config)
|
||||
|
||||
// Switch to Spotify
|
||||
err := c.SelectSource("SPOTIFY", "")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Switch to Bluetooth
|
||||
err = c.SelectSource("BLUETOOTH", "")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Switch to AUX input
|
||||
err = c.SelectSource("AUX", "")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("Source changed successfully")
|
||||
|
||||
// Output:
|
||||
// Source changed successfully
|
||||
}
|
||||
|
||||
// ExampleClient_SetBass demonstrates bass control.
|
||||
func ExampleClient_SetBass() {
|
||||
config := &client.Config{Host: "192.168.1.100"}
|
||||
c := client.NewClient(config)
|
||||
|
||||
// Set bass to +3 (range: -9 to +9)
|
||||
err := c.SetBass(3)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Get current bass level
|
||||
bass, err := c.GetBass()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Bass level: %d\n", bass.ActualBass)
|
||||
|
||||
// Output:
|
||||
// Bass level: 3
|
||||
}
|
||||
|
||||
// ExampleClient_SetBalance demonstrates balance control.
|
||||
func ExampleClient_SetBalance() {
|
||||
config := &client.Config{Host: "192.168.1.100"}
|
||||
c := client.NewClient(config)
|
||||
|
||||
// Set balance slightly to the right (range: -50 to +50)
|
||||
err := c.SetBalance(10)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Get current balance
|
||||
balance, err := c.GetBalance()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Balance: %d\n", balance.ActualBalance)
|
||||
|
||||
// Output:
|
||||
// Balance: 10
|
||||
}
|
||||
|
||||
// ExampleClient_SetZone demonstrates multiroom zone management.
|
||||
func ExampleClient_SetZone() {
|
||||
config := &client.Config{Host: "192.168.1.100"}
|
||||
c := client.NewClient(config)
|
||||
|
||||
// Create a zone with multiple speakers
|
||||
zone := &models.Zone{
|
||||
Master: "192.168.1.100",
|
||||
Members: []models.ZoneMember{
|
||||
{IPAddress: "192.168.1.101"},
|
||||
{IPAddress: "192.168.1.102"},
|
||||
},
|
||||
}
|
||||
|
||||
err := c.SetZone(zone)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("Zone created successfully")
|
||||
|
||||
// Output:
|
||||
// Zone created successfully
|
||||
}
|
||||
|
||||
// ExampleClient_GetPresets demonstrates how to retrieve configured presets.
|
||||
func ExampleClient_GetPresets() {
|
||||
config := &client.Config{Host: "192.168.1.100"}
|
||||
c := client.NewClient(config)
|
||||
|
||||
presets, err := c.GetPresets()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, preset := range presets.Presets {
|
||||
fmt.Printf("Preset %d: %s (%s)\n", preset.ID, preset.Name, preset.Source)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Preset 1: Morning Jazz (SPOTIFY)
|
||||
// Preset 2: Classic Rock (SPOTIFY)
|
||||
// Preset 3: NPR News (INTERNET_RADIO)
|
||||
}
|
||||
|
||||
// ExampleClient_SubscribeToEvents demonstrates real-time event monitoring.
|
||||
func ExampleClient_SubscribeToEvents() {
|
||||
config := &client.Config{Host: "192.168.1.100"}
|
||||
c := client.NewClient(config)
|
||||
|
||||
ctx := context.Background()
|
||||
events, err := c.SubscribeToEvents(ctx)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Monitor events for a short time
|
||||
timeout := time.After(5 * time.Second)
|
||||
|
||||
for {
|
||||
select {
|
||||
case event := <-events:
|
||||
switch e := event.(type) {
|
||||
case *models.NowPlayingUpdated:
|
||||
fmt.Printf("Track changed: %s by %s\n", e.Track, e.Artist)
|
||||
case *models.VolumeUpdated:
|
||||
fmt.Printf("Volume changed: %d\n", e.ActualVolume)
|
||||
}
|
||||
case <-timeout:
|
||||
fmt.Println("Event monitoring completed")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Track changed: Stairway to Heaven by Led Zeppelin
|
||||
// Volume changed: 65
|
||||
// Event monitoring completed
|
||||
}
|
||||
|
||||
// ExampleClient_SendKey demonstrates sending key commands.
|
||||
func ExampleClient_SendKey() {
|
||||
config := &client.Config{Host: "192.168.1.100"}
|
||||
c := client.NewClient(config)
|
||||
|
||||
// Send various key commands
|
||||
commands := []string{"PLAY", "PAUSE", "NEXT_TRACK", "PREV_TRACK", "MUTE"}
|
||||
|
||||
for _, cmd := range commands {
|
||||
err := c.SendKey(cmd, "press")
|
||||
if err != nil {
|
||||
log.Printf("Failed to send %s: %v", cmd, err)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("Sent command: %s\n", cmd)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Sent command: PLAY
|
||||
// Sent command: PAUSE
|
||||
// Sent command: NEXT_TRACK
|
||||
// Sent command: PREV_TRACK
|
||||
// Sent command: MUTE
|
||||
}
|
||||
|
||||
// ExampleClient_GetCapabilities demonstrates how to check device capabilities.
|
||||
func ExampleClient_GetCapabilities() {
|
||||
config := &client.Config{Host: "192.168.1.100"}
|
||||
c := client.NewClient(config)
|
||||
|
||||
capabilities, err := c.GetCapabilities()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Device supports %d sources\n", len(capabilities.Sources))
|
||||
for _, source := range capabilities.Sources {
|
||||
fmt.Printf("- %s (%s)\n", source.Source, source.SourceAccount)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Device supports 5 sources
|
||||
// - SPOTIFY (spotify_user123)
|
||||
// - BLUETOOTH ()
|
||||
// - AUX ()
|
||||
// - AIRPLAY ()
|
||||
// - INTERNET_RADIO ()
|
||||
}
|
||||
Reference in New Issue
Block a user