feat: show ContentItem location details for all sources in 'play now' command

- Add automatic display of ContentItem location (URI/ID) for all sources with location data
- Add --verbose flag to 'play now' command for detailed content information
- Show location details by default for any source (SPOTIFY, TUNEIN, PANDORA, STORED_MUSIC, etc.)
- Add comprehensive test coverage for content details display logic
- Add preset-store.md documentation for future /storePreset implementation
- Update documentation to reflect universal location support

This enables users to easily capture location URIs needed for the planned /storePreset feature:
- Spotify: spotify:track:123456789
- TUNEIN: /v1/playback/station/s33828
- Internet Radio: https://stream.example.com/radio
- NAS Music: 6_a2874b5d_4f83d999
- Pandora: 126740707481236361

Resolves #14 preparation work
This commit is contained in:
Tobias Gesellchen
2026-01-30 22:38:49 +01:00
parent c621f922e8
commit 63de381411
7 changed files with 2430 additions and 414 deletions
File diff suppressed because it is too large Load Diff
+300
View File
@@ -0,0 +1,300 @@
# SoundTouch API Comparison: Community Wiki vs Current Implementation
**Date:** January 2026
**Source:** [SoundTouch Plus Wiki](https://github.com/thlucas1/homeassistantcomponent_soundtouchplus/wiki/SoundTouch-WebServices-API)
**Our Implementation:** Bose-SoundTouch Go Library v1.0
## Executive Summary
The SoundTouch Plus community wiki documents **87 distinct API endpoints** with comprehensive examples, while our current implementation covers **23 endpoints**. This represents a significant opportunity to expand our API coverage from basic functionality to comprehensive SoundTouch ecosystem management.
### Key Findings
- 📊 **Wiki Coverage**: 87 endpoints documented with real-world examples
- 📊 **Our Coverage**: 23 endpoints implemented (26% of wiki coverage)
- 🎯 **Gap**: 64 additional endpoints available for implementation
- ⭐ **Quality**: Wiki provides production-ready XML examples and device-specific notes
---
## Implementation Status Matrix
### ✅ Already Implemented (23 endpoints)
| Endpoint | Wiki Status | Our Status | Notes |
|----------|-------------|------------|-------|
| `/info` | ✅ Documented | ✅ Complete | Device information |
| `/now_playing` | ✅ Documented | ✅ Complete | Current playback status |
| `/key` | ✅ Documented | ✅ Complete | Key press/release simulation |
| `/volume` | ✅ Documented | ✅ Complete | Volume and mute control |
| `/bass` | ✅ Documented | ✅ Complete | Bass level control |
| `/bassCapabilities` | ✅ Documented | ✅ Complete | Bass capability detection |
| `/sources` | ✅ Documented | ✅ Complete | Available audio sources |
| `/select` | ✅ Documented | ✅ Complete | Source selection |
| `/presets` | ✅ Documented | ✅ Complete | Preset configurations (read-only) |
| `/getZone` | ✅ Documented | ✅ Complete | Zone status and membership |
| `/setZone` | ✅ Documented | ✅ Complete | Zone creation and management |
| `/addZoneSlave` | ✅ Documented | ✅ Complete | Add device to zone |
| `/removeZoneSlave` | ✅ Documented | ✅ Complete | Remove device from zone |
| `/capabilities` | ✅ Documented | ✅ Complete | Device feature capabilities |
| `/audiodspcontrols` | ✅ Documented | ✅ Complete | Audio DSP modes and video sync |
| `/audioproducttonecontrols` | ✅ Documented | ✅ Complete | Advanced bass/treble controls |
| `/audioproductlevelcontrols` | ✅ Documented | ✅ Complete | Speaker level controls |
| `/name` (GET/POST) | ✅ Documented | ✅ Complete | Device name management |
| `/balance` | ✅ Documented | ✅ Complete | Stereo balance control |
| `/clockTime` | ✅ Documented | ✅ Complete | Device time management |
| `/clockDisplay` | ✅ Documented | ✅ Complete | Clock display settings |
| `/networkInfo` | ✅ Documented | ✅ Complete | Network connectivity info |
| `/requestToken` | ✅ Documented | ✅ Complete | Bearer token generation |
### 🔥 High Priority Missing (20 endpoints)
| Endpoint | Wiki Status | Priority | Use Case |
|----------|-------------|----------|----------|
| `/storePreset` | ✅ Detailed | **HIGH** | Save stations/playlists to presets |
| `/removePreset` | ✅ Detailed | **HIGH** | Delete saved presets |
| `/selectPreset` | ✅ Detailed | **HIGH** | Play preset by ID |
| `/setMusicServiceAccount` | ✅ Detailed | **HIGH** | Add Spotify/Pandora accounts |
| `/removeMusicServiceAccount` | ✅ Detailed | **HIGH** | Remove music service accounts |
| `/searchStation` | ✅ Detailed | **HIGH** | Find Pandora/Spotify content |
| `/addStation` | ✅ Detailed | **HIGH** | Add stations to favorites |
| `/removeStation` | ✅ Detailed | **HIGH** | Remove stations from favorites |
| `/navigate` | ✅ Detailed | **HIGH** | Browse music libraries/services |
| `/search` | ✅ Detailed | **HIGH** | Search music content |
| `/userPlayControl` | ✅ Detailed | **HIGH** | Play/pause/stop controls |
| `/userRating` | ✅ Detailed | **HIGH** | Thumbs up/down ratings |
| `/recents` | ✅ Detailed | **HIGH** | Recently played content |
| `/standby` | ✅ Detailed | **HIGH** | Power management |
| `/powerManagement` | ✅ Detailed | **HIGH** | Power state information |
| `/lowPowerStandby` | ✅ Detailed | **HIGH** | Low-power mode |
| `/listMediaServers` | ✅ Detailed | **HIGH** | UPnP/DLNA server discovery |
| `/serviceAvailability` | ✅ Detailed | **HIGH** | Source availability status |
| `/introspect` | ✅ Detailed | **HIGH** | Music service account status |
| `/language` | ✅ Detailed | **HIGH** | Device language settings |
### 🎵 Music Service Management (12 endpoints)
| Category | Endpoints | Wiki Coverage | Notes |
|----------|-----------|---------------|-------|
| **Account Management** | `/setMusicServiceAccount`, `/removeMusicServiceAccount` | ✅ Full XML examples | Pandora, Spotify, NAS setup |
| **Station Management** | `/searchStation`, `/addStation`, `/removeStation` | ✅ Pandora tested | Station discovery and favorites |
| **Content Navigation** | `/navigate`, `/search` | ✅ Detailed examples | Music library browsing |
| **Track Information** | `/trackInfo`, `/introspect` | ✅ Service-specific | Extended metadata |
### 🏠 Smart Home Integration (15 endpoints)
| Category | Endpoints | Wiki Coverage | Notes |
|----------|-----------|---------------|-------|
| **Notifications** | `/speaker`, `/playNotification` | ✅ TTS examples | Text-to-speech, URL playback |
| **Power Management** | `/standby`, `/powerManagement`, `/lowPowerStandby` | ✅ Complete | Smart home automation |
| **Network Management** | `/performWirelessSiteSurvey`, `/addWirelessProfile`, `/getActiveWirelessProfile` | ✅ WiFi setup | Network configuration |
| **Bluetooth** | `/enterBluetoothPairing`, `/clearBluetoothPaired`, `/bluetoothInfo` | ✅ Pairing control | Bluetooth management |
| **Source Control** | `/selectLastSource`, `/selectLastSoundTouchSource`, `/selectLocalSource` | ✅ Source switching | Quick source access |
### 📱 Advanced Device Features (19 endpoints)
| Category | Endpoints | Wiki Coverage | Notes |
|----------|-----------|---------------|-------|
| **Stereo Pairs** | `/getGroup`, `/addGroup`, `/removeGroup`, `/updateGroup` | ✅ ST-10 specific | L/R speaker pairing |
| **System Info** | `/soundTouchConfigurationStatus`, `/systemtimeout`, `/rebroadcastlatencymode` | ✅ Configuration | Device state management |
| **Software Updates** | `/swUpdateCheck`, `/swUpdateQuery`, `/swUpdateAbort`, `/swUpdateStart` | ✅ Update process | Firmware management |
| **Audio Processing** | `/DSPMonoStereo`, `/audiospeakerattributeandsetting` | ✅ Hardware-specific | Advanced audio features |
---
## Wiki Documentation Quality Analysis
### 🌟 Exceptional Documentation Quality
**Real-World Examples:**
- ✅ Complete XML request/response examples
- ✅ Device-specific behavior notes (ST-10 vs ST-300)
- ✅ Error conditions and troubleshooting
- ✅ WebSocket event generation documentation
- ✅ Service-specific requirements (Pandora Premium, etc.)
**Production-Ready Details:**
```xml
<!-- Example from wiki - POST /storePreset -->
<preset id="3" createdOn="1701220500" updatedOn="1701220500">
<ContentItem source="TUNEIN" type="stationurl" location="/v1/playback/station/s309605" sourceAccount="" isPresetable="true">
<itemName>K-LOVE 90s</itemName>
<containerArt>http://cdn-profiles.tunein.com/s309605/images/logog.png</containerArt>
</ContentItem>
</preset>
```
**Device Compatibility Matrix:**
- ST-10: Supports notifications, stereo pairing
- ST-300: Supports advanced audio controls, HDMI
- All devices: Support basic playback and zone management
### 🎯 Implementation Guidance
**Safety Notes from Wiki:**
- Volume limits: Devices auto-limit 10-70 for notifications
- Timeout handling: Some endpoints timeout on unsupported devices
- State requirements: Certain operations require specific device states
**WebSocket Events Documented:**
- `presetsUpdated` - Preset changes
- `groupUpdated` - Stereo pair changes
- `zoneUpdated` - Multi-room changes
- `nowPlayingUpdated` - Source/playback changes
- `volumeUpdated` - Volume/mute changes
- `audiodspcontrols` - Audio mode changes
---
## Implementation Roadmap
### Phase 1: Essential Missing Features (High Impact)
**Target: 20 endpoints in 4 weeks**
```go
// Preset Management
func (c *Client) StorePreset(id int, content ContentItem) error
func (c *Client) RemovePreset(id int) error
func (c *Client) SelectPreset(id int) error
// Music Service Setup
func (c *Client) SetMusicServiceAccount(source, user, pass string) error
func (c *Client) RemoveMusicServiceAccount(source, user string) error
// Content Discovery
func (c *Client) NavigateLibrary(source, account string, startItem, numItems int) (*NavigateResponse, error)
func (c *Client) SearchContent(source, account, term string) (*SearchResponse, error)
// Power Management
func (c *Client) Standby() error
func (c *Client) GetPowerState() (*PowerState, error)
```
### Phase 2: Smart Home Integration (Medium Impact)
**Target: 15 endpoints in 3 weeks**
```go
// Notification System
func (c *Client) PlayTTSMessage(message string, volume int) error
func (c *Client) PlayURL(url string, volume int) error
// Network Management
func (c *Client) PerformWiFiSurvey() (*WiFiNetworks, error)
func (c *Client) AddWiFiProfile(ssid, password, securityType string) error
// Enhanced Controls
func (c *Client) SendPlayControl(action PlayControlAction) error
func (c *Client) RateCurrentTrack(rating RatingValue) error
```
### Phase 3: Advanced Features (Lower Impact)
**Target: 19 endpoints in 4 weeks**
```go
// Stereo Pair Management
func (c *Client) CreateStereoPair(leftIP, rightIP string, name string) error
func (c *Client) GetStereoPairStatus() (*StereoPair, error)
// System Management
func (c *Client) CheckSoftwareUpdate() (*UpdateInfo, error)
func (c *Client) GetSystemTimeout() (*TimeoutConfig, error)
```
---
## Integration Benefits
### 🏆 Complete Ecosystem Support
- **Music Services**: Full Spotify, Pandora, NAS integration
- **Smart Home**: Power, notifications, network management
- **Professional**: Advanced audio controls, system configuration
### 🔧 Developer Experience
- **Comprehensive Examples**: Wiki provides copy-paste XML structures
- **Error Handling**: Well-documented failure modes and recovery
- **Device Compatibility**: Clear hardware-specific feature matrix
### 📈 Use Case Expansion
- **Home Automation**: Complete power and network control
- **Music Management**: Full playlist and station management
- **Professional Audio**: Advanced DSP and speaker configuration
- **System Administration**: Update management and configuration
---
## Technical Implementation Notes
### Request/Response Patterns from Wiki
**Standard Success Response:**
```xml
<?xml version="1.0" encoding="UTF-8" ?>
<status>/endpointName</status>
```
**Complex Response Example (from `/navigate`):**
```xml
<navigateResponse source="STORED_MUSIC" sourceAccount="guid/0">
<totalItems>10</totalItems>
<items>
<item Playable="1">
<name>Album Artists</name>
<type>dir</type>
<ContentItem source="STORED_MUSIC" location="107" sourceAccount="guid/0" isPresetable="true">
<itemName>Album Artists</itemName>
</ContentItem>
</item>
</items>
</navigateResponse>
```
### Error Handling Patterns
**Device Compatibility:**
```go
// Check capabilities before calling advanced features
capabilities, err := client.GetCapabilities()
if err != nil {
return err
}
if !capabilities.SupportsAudioDSPControls {
return ErrFeatureNotSupported
}
```
### WebSocket Event Integration
Each POST endpoint maps to specific WebSocket events that our existing event system can handle:
```go
// Extend existing event system
type WebSocketEvent struct {
PresetUpdated *PresetsUpdate `xml:"presetsUpdated"`
GroupUpdated *GroupUpdate `xml:"groupUpdated"`
// Add new event types...
}
```
---
## Conclusion
The SoundTouch Plus Wiki represents a **treasure trove** of production-ready API documentation that can transform our library from basic device control to comprehensive SoundTouch ecosystem management.
### Key Opportunities:
- 🎯 **3x Coverage Expansion**: From 23 to 87+ endpoints
- 🏠 **Smart Home Ready**: Complete automation integration
- 🎵 **Music Service Integration**: Full streaming service support
- 📱 **Professional Features**: Advanced audio and system control
- ✅ **Production Ready**: Real-world tested examples and error handling
### Immediate Next Steps:
1. **Phase 1 Implementation**: Focus on preset management and music services (high user impact)
2. **Test Infrastructure**: Set up automated testing against real devices
3. **Documentation**: Integrate wiki examples into our API documentation
4. **Community Engagement**: Collaborate with SoundTouch Plus project for mutual benefit
**This wiki documentation provides everything needed to implement a complete, production-ready SoundTouch API library that rivals official Bose applications in functionality.**
---
*Note: All endpoints documented in the wiki are tested against real hardware. Device-specific limitations are clearly documented with compatibility matrices for ST-10, ST-300, and other SoundTouch models.*
+632
View File
@@ -0,0 +1,632 @@
# SoundTouch API Wiki Implementation Plan
**Date:** January 2026
**Source:** [SoundTouch Plus Wiki](https://github.com/thlucas1/homeassistantcomponent_soundtouchplus/wiki/SoundTouch-WebServices-API)
**Target:** Complete implementation of 64 additional endpoints from wiki documentation
## Project Overview
### Scope
Implement 64 additional API endpoints documented in the SoundTouch Plus Wiki to achieve comprehensive SoundTouch ecosystem coverage.
### Current Status
- ✅ **Implemented**: 23 endpoints (core functionality)
- 🎯 **Target**: 87 endpoints (comprehensive functionality)
- 📈 **Expansion**: 3.8x increase in API coverage
---
## Implementation Phases
## Phase 1: Essential User Features (4 weeks)
**Priority:** CRITICAL
**Endpoints:** 20
**User Impact:** HIGH
### 1.1 Preset Management (Week 1)
Essential for user experience - save and manage favorite stations/playlists.
#### Endpoints to Implement:
```go
// pkg/api/presets.go (new file)
func (c *Client) StorePreset(id int, content ContentItem) error
func (c *Client) RemovePreset(id int) error
func (c *Client) SelectPreset(id int) error
```
#### XML Structures:
```xml
<!-- Store Preset Request -->
<preset id="3" createdOn="1701220500" updatedOn="1701220500">
<ContentItem source="TUNEIN" type="stationurl" location="/v1/playback/station/s309605" sourceAccount="" isPresetable="true">
<itemName>K-LOVE 90s</itemName>
<containerArt>http://cdn-profiles.tunein.com/s309605/images/logog.png</containerArt>
</ContentItem>
</preset>
<!-- Remove Preset Request -->
<preset id="4"></preset>
```
#### WebSocket Events:
- `presetsUpdated` - Triggered on store/remove operations
### 1.2 Music Service Management (Week 1-2)
Critical for streaming service integration - Spotify, Pandora, NAS libraries.
#### Endpoints to Implement:
```go
// pkg/api/music_services.go (new file)
func (c *Client) SetMusicServiceAccount(source, user, password, displayName string) error
func (c *Client) RemoveMusicServiceAccount(source, user string) error
func (c *Client) ListMediaServers() (*MediaServerList, error)
func (c *Client) GetServiceAvailability() (*ServiceAvailability, error)
```
#### Service Types:
```go
type MusicService string
const (
ServicePandora MusicService = "PANDORA"
ServiceSpotify MusicService = "SPOTIFY"
ServiceStoredMusic MusicService = "STORED_MUSIC"
ServiceLocalMusic MusicService = "LOCAL_MUSIC"
)
type MediaServer struct {
ID string `xml:"id,attr"`
MAC string `xml:"mac,attr"`
IP string `xml:"ip,attr"`
Manufacturer string `xml:"manufacturer,attr"`
ModelName string `xml:"model_name,attr"`
FriendlyName string `xml:"friendly_name,attr"`
Location string `xml:"location,attr"`
}
```
#### XML Examples:
```xml
<!-- Pandora Account Setup -->
<credentials source="PANDORA" displayName="Pandora Music Service">
<user>YourPandoraUserId</user>
<pass>YourPandoraPassword$1pd</pass>
</credentials>
<!-- NAS Library Setup -->
<credentials source="STORED_MUSIC" displayName="My NAS Media Library:">
<user>d09708a1-5953-44bc-a413-123456789012/0</user>
<pass />
</credentials>
```
### 1.3 Content Discovery (Week 2-3)
Essential for browsing music libraries and searching content.
#### Endpoints to Implement:
```go
// pkg/api/content.go (new file)
func (c *Client) Navigate(source, sourceAccount string, options NavigateOptions) (*NavigateResponse, error)
func (c *Client) Search(source, sourceAccount, searchTerm string, options SearchOptions) (*SearchResponse, error)
func (c *Client) GetRecents() (*RecentsResponse, error)
func (c *Client) Introspect(source, sourceAccount string) (*IntrospectResponse, error)
```
#### Data Structures:
```go
type NavigateOptions struct {
StartItem int `xml:"startItem"`
NumItems int `xml:"numItems"`
Item *ContentItem `xml:"item,omitempty"`
Sort string `xml:"sort,attr,omitempty"`
Menu string `xml:"menu,attr,omitempty"`
}
type NavigateResponse struct {
Source string `xml:"source,attr"`
SourceAccount string `xml:"sourceAccount,attr"`
TotalItems int `xml:"totalItems"`
Items []ContentItem `xml:"items>item"`
}
type SearchOptions struct {
StartItem int `xml:"startItem"`
NumItems int `xml:"numItems"`
Filter string `xml:"searchTerm,attr,omitempty"` // "track", "artist", "album"
}
```
### 1.4 Station Management (Week 3)
Pandora and other music service station management.
#### Endpoints to Implement:
```go
// pkg/api/stations.go (new file)
func (c *Client) SearchStations(source, sourceAccount, searchTerm string) (*StationSearchResponse, error)
func (c *Client) AddStation(source, sourceAccount, token, name string) error
func (c *Client) RemoveStation(content ContentItem) error
```
### 1.5 Enhanced Playback Control (Week 4)
Advanced playback and rating controls.
#### Endpoints to Implement:
```go
// pkg/api/playback.go (extend existing)
func (c *Client) SendPlayControl(action PlayControlAction) error
func (c *Client) RateCurrentTrack(rating RatingValue) error
```
#### Enums:
```go
type PlayControlAction string
const (
PlayControlPause PlayControlAction = "PAUSE_CONTROL"
PlayControlPlay PlayControlAction = "PLAY_CONTROL"
PlayControlPlayPause PlayControlAction = "PLAY_PAUSE_CONTROL"
PlayControlStop PlayControlAction = "STOP_CONTROL"
)
type RatingValue string
const (
RatingUp RatingValue = "UP"
RatingDown RatingValue = "DOWN"
)
```
### 1.6 Power Management (Week 4)
Essential for smart home integration.
#### Endpoints to Implement:
```go
// pkg/api/power.go (new file)
func (c *Client) Standby() error
func (c *Client) GetPowerState() (*PowerState, error)
func (c *Client) SetLowPowerStandby() error
```
---
## Phase 2: Smart Home Integration (3 weeks)
**Priority:** HIGH
**Endpoints:** 15
**User Impact:** MEDIUM-HIGH
### 2.1 Notification System (Week 1)
Text-to-speech and URL playback for smart home notifications.
#### Endpoints to Implement:
```go
// pkg/api/notifications.go (new file)
func (c *Client) PlayTTSMessage(message string, options TTSOptions) error
func (c *Client) PlayURL(url string, options PlayOptions) error
func (c *Client) PlayNotificationBeep() error
```
#### Data Structures:
```go
type TTSOptions struct {
VolumeLevel int `xml:"volume,omitempty"`
Language string `xml:"tl,omitempty"` // "EN", "DE", etc.
AppKey string `xml:"app_key"`
Service string `xml:"service"`
Message string `xml:"message"`
Reason string `xml:"reason"`
}
type PlayOptions struct {
VolumeLevel int `xml:"volume,omitempty"`
AppKey string `xml:"app_key"`
Service string `xml:"service"`
Message string `xml:"message"`
Reason string `xml:"reason"`
}
```
#### XML Examples:
```xml
<!-- TTS Message -->
<play_info>
<url>http://translate.google.com/translate_tts?ie=UTF-8&amp;tl=EN&amp;client=tw-ob&amp;q=There%20is%20activity%20at%20the%20front%20door.</url>
<app_key>YourAppKey</app_key>
<service>TTS Notification</service>
<message>Google TTS</message>
<reason>There is activity at the front door.</reason>
<volume>70</volume>
</play_info>
```
### 2.2 Network Management (Week 2)
WiFi configuration and network information.
#### Endpoints to Implement:
```go
// pkg/api/network.go (extend existing)
func (c *Client) PerformWiFiSurvey() (*WiFiSurveyResponse, error)
func (c *Client) AddWiFiProfile(ssid, password string, securityType SecurityType) error
func (c *Client) GetActiveWiFiProfile() (*WiFiProfile, error)
func (c *Client) GetNetworkStats() (*NetworkStats, error)
```
#### Security Types:
```go
type SecurityType string
const (
SecurityNone SecurityType = "none"
SecurityWEP SecurityType = "wep"
SecurityWPATKIP SecurityType = "wpatkip"
SecurityWPAAES SecurityType = "wpaaes"
SecurityWPA2TKIP SecurityType = "wpa2tkip"
SecurityWPA2AES SecurityType = "wpa2aes"
SecurityWPAOrWPA2 SecurityType = "wpa_or_wpa2" // Recommended
)
```
### 2.3 Bluetooth Management (Week 2)
Bluetooth pairing and connection management.
#### Endpoints to Implement:
```go
// pkg/api/bluetooth.go (new file)
func (c *Client) EnterBluetoothPairing() error
func (c *Client) ClearBluetoothPairings() error
func (c *Client) GetBluetoothInfo() (*BluetoothInfo, error)
```
### 2.4 Language and System Configuration (Week 3)
Device language and system settings.
#### Endpoints to Implement:
```go
// pkg/api/system.go (new file)
func (c *Client) GetLanguage() (LanguageCode, error)
func (c *Client) SetLanguage(lang LanguageCode) error
func (c *Client) GetConfigurationStatus() (*ConfigurationStatus, error)
func (c *Client) GetSystemTimeout() (*SystemTimeout, error)
```
#### Language Codes:
```go
type LanguageCode int
const (
LangDanish LanguageCode = 1
LangGerman LanguageCode = 2
LangEnglish LanguageCode = 3
LangSpanish LanguageCode = 4
LangFrench LanguageCode = 5
LangItalian LanguageCode = 6
LangDutch LanguageCode = 7
LangSwedish LanguageCode = 8
LangJapanese LanguageCode = 9
LangSimplifiedChinese LanguageCode = 10
LangTraditionalChinese LanguageCode = 11
LangKorean LanguageCode = 12
)
```
---
## Phase 3: Advanced Features (4 weeks)
**Priority:** MEDIUM
**Endpoints:** 19
**User Impact:** MEDIUM
### 3.1 Stereo Pair Management (Week 1)
ST-10 specific left/right speaker pairing.
#### Endpoints to Implement:
```go
// pkg/api/groups.go (new file)
func (c *Client) GetStereoPairStatus() (*StereoPair, error)
func (c *Client) CreateStereoPair(leftDeviceID, rightDeviceID string, name string) (*StereoPair, error)
func (c *Client) RemoveStereoPair() error
func (c *Client) UpdateStereoPairName(groupID, newName string) (*StereoPair, error)
```
#### Data Structures:
```go
type StereoPair struct {
ID string `xml:"id,attr"`
Name string `xml:"name"`
MasterDeviceID string `xml:"masterDeviceId"`
Roles []GroupRole `xml:"roles>groupRole"`
SenderIPAddress string `xml:"senderIPAddress"`
Status string `xml:"status"`
}
type GroupRole struct {
DeviceID string `xml:"deviceId"`
Role string `xml:"role"` // "LEFT", "RIGHT"
IPAddress string `xml:"ipAddress"`
}
```
### 3.2 Software Update Management (Week 2)
Firmware update checking and management.
#### Endpoints to Implement:
```go
// pkg/api/updates.go (new file)
func (c *Client) CheckSoftwareUpdate() (*UpdateInfo, error)
func (c *Client) GetUpdateStatus() (*UpdateStatus, error)
func (c *Client) StartSoftwareUpdate() error
func (c *Client) AbortSoftwareUpdate() error
```
### 3.3 Advanced Audio Features (Week 3)
Advanced DSP and speaker configuration.
#### Endpoints to Implement:
```go
// pkg/api/audio_advanced.go (new file)
func (c *Client) GetDSPMonoStereo() (*DSPMonoStereoConfig, error)
func (c *Client) SetDSPMonoStereo(enabled bool) error
func (c *Client) GetAudioSpeakerAttributes() (*SpeakerAttributes, error)
func (c *Client) GetRebroadcastLatencyMode() (*LatencyMode, error)
```
### 3.4 Source Selection Shortcuts (Week 4)
Quick source switching utilities.
#### Endpoints to Implement:
```go
// pkg/api/sources.go (extend existing)
func (c *Client) SelectLastSource() error
func (c *Client) SelectLastSoundTouchSource() error
func (c *Client) SelectLastWiFiSource() error
func (c *Client) SelectLocalSource() error
```
---
## Phase 4: Professional Features (2 weeks)
**Priority:** LOW
**Endpoints:** 10
**User Impact:** LOW
### 4.1 HDMI and Product Controls
ST-300 specific HDMI and product controls.
#### Endpoints to Implement:
```go
// pkg/api/product.go (new file)
func (c *Client) GetProductCECHDMIControl() (*CECHDMIControl, error)
func (c *Client) SetProductCECHDMIControl(config CECHDMIControl) error
func (c *Client) GetProductHDMIAssignmentControls() (*HDMIAssignmentControls, error)
func (c *Client) SetProductHDMIAssignmentControls(config HDMIAssignmentControls) error
```
### 4.2 System Administration
Advanced system configuration and diagnostics.
#### Endpoints to Implement:
```go
// pkg/api/admin.go (new file)
func (c *Client) GetCriticalErrors() (*CriticalErrors, error)
func (c *Client) PerformFactoryDefault() error
func (c *Client) GetBCOReset() (*BCOResetStatus, error)
func (c *Client) SetBCOReset(enabled bool) error
```
---
## Implementation Guidelines
### File Structure
```
pkg/
├── api/
│ ├── presets.go (Phase 1.1)
│ ├── music_services.go (Phase 1.2)
│ ├── content.go (Phase 1.3)
│ ├── stations.go (Phase 1.4)
│ ├── playback.go (Phase 1.5 - extend existing)
│ ├── power.go (Phase 1.6)
│ ├── notifications.go (Phase 2.1)
│ ├── network.go (Phase 2.2 - extend existing)
│ ├── bluetooth.go (Phase 2.3)
│ ├── system.go (Phase 2.4)
│ ├── groups.go (Phase 3.1)
│ ├── updates.go (Phase 3.2)
│ ├── audio_advanced.go (Phase 3.3)
│ ├── sources.go (Phase 3.4 - extend existing)
│ ├── product.go (Phase 4.1)
│ └── admin.go (Phase 4.2)
├── types/
│ ├── presets.go
│ ├── music_services.go
│ ├── content.go
│ ├── notifications.go
│ ├── network.go
│ ├── bluetooth.go
│ ├── system.go
│ ├── groups.go
│ ├── updates.go
│ └── product.go
└── websocket/
└── events.go (extend with new event types)
```
### Error Handling Strategy
#### Device Capability Checking
```go
// Always check capabilities before calling advanced features
func (c *Client) callAdvancedEndpoint() error {
capabilities, err := c.GetCapabilities()
if err != nil {
return fmt.Errorf("failed to get capabilities: %w", err)
}
if !capabilities.SupportsFeature("targetFeature") {
return ErrFeatureNotSupported
}
// Proceed with endpoint call
}
```
#### Timeout Handling
```go
// Some endpoints timeout on unsupported devices
func (c *Client) callWithTimeout(endpoint string) error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// Make request with context
if err := c.makeRequest(ctx, endpoint); err != nil {
if errors.Is(err, context.DeadlineExceeded) {
return ErrEndpointNotSupported
}
return err
}
return nil
}
```
### Testing Strategy
#### Unit Tests
- XML marshaling/unmarshaling for all new types
- Error handling scenarios
- Input validation
#### Integration Tests
- Real device testing for each endpoint
- Device compatibility matrix validation
- WebSocket event verification
#### Device Matrix Testing
```go
var deviceTests = []struct {
model string
endpoints []string
supported bool
}{
{"ST-10", []string{"/playNotification", "/getGroup"}, true},
{"ST-300", []string{"/audiodspcontrols", "/productcechdmicontrol"}, true},
{"ST-10", []string{"/audiodspcontrols"}, false},
}
```
### WebSocket Event Integration
#### Extend Existing Event System
```go
// pkg/websocket/events.go (extend existing)
type WebSocketEvent struct {
// Existing events...
VolumeUpdated *VolumeUpdate `xml:"volumeUpdated"`
NowPlayingUpdated *NowPlayingUpdate `xml:"nowPlayingUpdated"`
// New events from wiki
PresetsUpdated *PresetsUpdate `xml:"presetsUpdated"`
GroupUpdated *GroupUpdate `xml:"groupUpdated"`
AudioDSPUpdated *AudioDSPUpdate `xml:"audiodspcontrols"`
ToneControlsUpdated *ToneUpdate `xml:"audioproducttonecontrols"`
LevelControlsUpdated *LevelUpdate `xml:"audioproductlevelcontrols"`
}
```
### Documentation Integration
#### Wiki Examples in Go Docs
```go
// StorePreset saves a preset to the device (maximum 6 presets).
//
// Example from SoundTouch Plus Wiki:
// preset := PresetData{
// ID: 3,
// ContentItem: ContentItem{
// Source: "TUNEIN",
// Type: "stationurl",
// Location: "/v1/playback/station/s309605",
// IsPresetable: true,
// ItemName: "K-LOVE 90s",
// ContainerArt: "http://cdn-profiles.tunein.com/s309605/images/logog.png",
// },
// }
// err := client.StorePreset(preset.ID, preset.ContentItem)
//
// This generates a presetsUpdated WebSocket event.
func (c *Client) StorePreset(id int, content ContentItem) error
```
---
## Success Metrics
### Phase 1 Completion Criteria
- [ ] All 20 endpoints implemented with full XML support
- [ ] Comprehensive unit test coverage (>90%)
- [ ] Real device testing on ST-10 and ST-300
- [ ] Documentation with wiki examples
- [ ] WebSocket event integration
### Phase 2 Completion Criteria
- [ ] Smart home integration examples
- [ ] Network management automation
- [ ] Notification system with TTS
- [ ] Bluetooth management
- [ ] Language configuration
### Phase 3 Completion Criteria
- [ ] Stereo pair management
- [ ] Software update automation
- [ ] Advanced audio features
- [ ] Source switching utilities
### Phase 4 Completion Criteria
- [ ] Professional HDMI controls
- [ ] System administration features
- [ ] Complete device capability matrix
- [ ] Production deployment guide
### Overall Success Metrics
- ✅ 87+ total endpoints implemented
- ✅ Complete SoundTouch ecosystem coverage
- ✅ Production-ready error handling
- ✅ Comprehensive documentation
- ✅ Real-world testing validation
- ✅ Community collaboration with SoundTouch Plus project
---
## Risk Mitigation
### Technical Risks
1. **Device Compatibility**: Test each endpoint on multiple device models
2. **Timeout Issues**: Implement capability checking before endpoint calls
3. **XML Complexity**: Thorough marshaling/unmarshaling tests
4. **WebSocket Events**: Validate event generation for all POST operations
### Schedule Risks
1. **Resource Availability**: Prioritize high-impact endpoints first
2. **Device Access**: Arrange access to multiple SoundTouch models
3. **Complexity Underestimation**: Buffer time in each phase
4. **Integration Issues**: Continuous integration testing
### Quality Risks
1. **Incomplete Testing**: Mandate real device validation
2. **Poor Documentation**: Use wiki examples in all documentation
3. **Breaking Changes**: Maintain backward compatibility
4. **Performance**: Benchmark all new endpoints
---
## Conclusion
This implementation plan leverages the comprehensive SoundTouch Plus Wiki to transform our library from basic device control to complete ecosystem management. The phased approach prioritizes user-facing features while ensuring quality and maintainability.
**Key Benefits:**
- 🎯 **3.8x API Coverage Expansion**: From 23 to 87+ endpoints
- 🏠 **Complete Smart Home Integration**: Power, notifications, network management
- 🎵 **Full Music Service Support**: Spotify, Pandora, NAS libraries
- ✅ **Production-Ready Implementation**: Real-world tested examples
- 📚 **Comprehensive Documentation**: Wiki integration and examples
**Timeline:** 13 weeks total for complete implementation
**Resources:** 1-2 developers with access to multiple SoundTouch devices
**Outcome:** Industry-leading SoundTouch API library with complete ecosystem support
*This plan transforms our library into the definitive Go implementation for SoundTouch integration, suitable for everything from basic home automation to professional audio installations.*
+377
View File
@@ -0,0 +1,377 @@
# SoundTouch `/storePreset` Implementation Guide
## Overview
This document analyzes the feasibility and implementation approach for adding `/storePreset` functionality to the Bose SoundTouch API client, based on [GitHub Issue #14](https://github.com/gesellix/Bose-SoundTouch/issues/14).
## Current Implementation Status
### ✅ Already Implemented
- `GetPresets()` - Read presets from device
- `SelectPreset()` - Select preset by number (1-6)
- `GetNextAvailablePresetSlot()` - Find next available preset slot
- `IsCurrentContentPresetable()` - Check if current content can be saved as preset
- Complete data models (`models.Preset`, `models.ContentItem`)
- WebSocket events for preset updates
### ❌ Missing Functionality
- `StorePreset()` - Save content as preset
- `RemovePreset()` - Delete existing preset
## API Capabilities
According to the [SoundTouch WebServices API Wiki](https://github.com/thlucas1/homeassistantcomponent_soundtouchplus/wiki/SoundTouch-WebServices-API#preset-store), `/storePreset` supports:
1. **Radio Stations** (TUNEIN, LOCAL_INTERNET_RADIO)
2. **Spotify Content** (Playlists, Albums, Artists, Tracks)
3. **Local Music** (STORED_MUSIC, LOCAL_MUSIC)
4. **Maximum 6 Presets** per device
5. **Automatic Timestamps** (createdOn, updatedOn)
6. **WebSocket Events** (`presetsUpdated`)
## Implementation Examples
### Core Client Methods
```go
// StorePreset saves content as a preset on the SoundTouch device
func (c *Client) StorePreset(id int, contentItem *models.ContentItem) error {
now := time.Now().Unix()
preset := &models.Preset{
ID: id,
CreatedOn: &now,
UpdatedOn: &now,
ContentItem: contentItem,
}
var response models.Presets
return c.post("/storePreset", preset, &response)
}
// RemovePreset deletes a preset from the SoundTouch device
func (c *Client) RemovePreset(id int) error {
preset := &models.Preset{ID: id}
var response models.Presets
return c.post("/removePreset", preset, &response)
}
// StoreCurrentAsPreset saves currently playing content as preset
func (c *Client) StoreCurrentAsPreset(id int) error {
nowPlaying, err := c.GetNowPlaying()
if err != nil {
return fmt.Errorf("failed to get current content: %w", err)
}
if !nowPlaying.ContentItem.IsPresetable {
return fmt.Errorf("current content is not presetable")
}
return c.StorePreset(id, nowPlaying.ContentItem)
}
```
### CLI Commands
```bash
# Store currently playing content as preset
soundtouch-cli --host 192.168.1.100 preset store-current --slot 3
# Store specific content as preset
soundtouch-cli --host 192.168.1.100 preset store \
--slot 1 \
--source SPOTIFY \
--location "spotify:playlist:37i9dQZF1DX0XUsuxWHRQd" \
--source-account "yourusername" \
--name "My Worship Mix"
# Store radio station as preset
soundtouch-cli --host 192.168.1.100 preset store \
--slot 2 \
--source TUNEIN \
--location "/v1/playback/station/s33828" \
--name "K-LOVE Radio"
# Remove preset
soundtouch-cli --host 192.168.1.100 preset remove --slot 3
# Show current content details (including location URI for all sources)
soundtouch-cli --host 192.168.1.100 play now
# Show detailed content information
soundtouch-cli --host 192.168.1.100 play now --verbose
```
## Spotify Integration Examples
### 1. Spotify Playlist
```go
contentItem := &models.ContentItem{
Source: "SPOTIFY",
Type: "uri",
Location: "spotify:playlist:37i9dQZF1DX0XUsuxWHRQd",
SourceAccount: "yourspotifyusername",
IsPresetable: true,
ItemName: "My Worship Mix",
ContainerArt: "https://i.scdn.co/image/ab67706c0000da84820d2514932c9e2ea40f6473",
}
```
### 2. Spotify Album
```go
contentItem := &models.ContentItem{
Source: "SPOTIFY",
Type: "uri",
Location: "spotify:album:6vc9OTcyd3hyzabCmsdnwE",
SourceAccount: "yourspotifyusername",
IsPresetable: true,
ItemName: "Welcome to the New",
ContainerArt: "https://i.scdn.co/image/ab67616d0000b27316c019c87a927829804caf0b",
}
```
### 3. Spotify Artist
```go
contentItem := &models.ContentItem{
Source: "SPOTIFY",
Type: "uri",
Location: "spotify:artist:6APm8EjxOHSYM5B4i3vT3q",
SourceAccount: "yourspotifyusername",
IsPresetable: true,
ItemName: "MercyMe",
ContainerArt: "https://i.scdn.co/image/ab6761610000e5eb16c019c87a927829804caf0b",
}
```
## Getting Spotify URIs (Location Values)
### Method 1: From Spotify App
1. Right-click on playlist/album/song in Spotify app
2. "Share" → "Copy link to playlist"
3. Convert URL to URI:
- URL: `https://open.spotify.com/playlist/37i9dQZF1DX0XUsuxWHRQd`
- URI: `spotify:playlist:37i9dQZF1DX0XUsuxWHRQd`
### Method 2: From Currently Playing Content (All Sources)
```go
func getCurrentContentLocation(client *soundtouch.Client) (string, string, error) {
nowPlaying, err := client.GetNowPlaying()
if err != nil {
return "", "", err
}
if nowPlaying.ContentItem == nil || nowPlaying.ContentItem.Location == "" {
return "", "", fmt.Errorf("no content location available")
}
return nowPlaying.ContentItem.Location, nowPlaying.ContentItem.Source, nil
}
```
### Method 3: URL to URI Converter
```go
func SpotifyURLToURI(url string) (string, error) {
re := regexp.MustCompile(`https://open\.spotify\.com/(playlist|album|artist|track|episode|show)/([a-zA-Z0-9]+)`)
matches := re.FindStringSubmatch(url)
if len(matches) != 3 {
return "", fmt.Errorf("invalid Spotify URL format")
}
contentType := matches[1]
contentID := matches[2]
return fmt.Sprintf("spotify:%s:%s", contentType, contentID), nil
}
```
## XML Request Format
The actual XML request sent to the SoundTouch API:
```xml
<preset id="3" createdOn="1701220500" updatedOn="1701220500">
<ContentItem source="SPOTIFY" type="uri" location="spotify:playlist:37i9dQZF1DX0XUsuxWHRQd" sourceAccount="yourusername" isPresetable="true">
<itemName>My Worship Mix</itemName>
<containerArt>https://i.scdn.co/image/ab67706c0000da84820d2514932c9e2ea40f6473</containerArt>
</ContentItem>
</preset>
```
## Radio Station Examples
### TUNEIN Radio
```go
contentItem := &models.ContentItem{
Source: "TUNEIN",
Type: "stationurl",
Location: "/v1/playback/station/s33828",
SourceAccount: "",
IsPresetable: true,
ItemName: "K-LOVE Radio",
ContainerArt: "http://cdn-profiles.tunein.com/s33828/images/logog.png",
}
```
### Local Internet Radio
```go
contentItem := &models.ContentItem{
Source: "LOCAL_INTERNET_RADIO",
Type: "stationurl",
Location: "https://content.api.bose.io/core02/svc-bmx-adapter-orion/prod/orion/station?data=eyJ...",
SourceAccount: "",
IsPresetable: true,
ItemName: "Custom Radio Station",
ContainerArt: "",
}
```
## Implementation Roadmap
### Phase 1: Core Functionality
1. Add `StorePreset()` method to client
2. Add `RemovePreset()` method to client
3. Add basic CLI commands
4. Add unit tests
### Phase 2: Enhanced CLI
1. Add `store-current` command
2. Add Spotify URL-to-URI conversion
3. Add content validation
4. Add batch import functionality
### Phase 3: Advanced Features
1. Add preset management utilities
2. Add content discovery helpers
3. Add preset backup/restore
4. Integration with Spotify Web API for search
## Technical Requirements
### Prerequisites
- Existing HTTP client infrastructure ✅
- XML marshaling/unmarshaling ✅
- WebSocket event system ✅
- CLI framework ✅
- Data models ✅
### Implementation Effort
- **Client methods**: ~50-100 lines of code
- **CLI commands**: ~100-150 lines of code
- **Tests**: ~200-300 lines of code
- **Documentation**: This document + API docs
## WebSocket Events
When presets are stored or removed, the device generates `presetsUpdated` events:
```xml
<updates deviceID="1004567890AA">
<presetsUpdated>
<presets>
<preset id="1" createdOn="1700536011" updatedOn="1700536011">
<ContentItem source="SPOTIFY" type="uri" location="spotify:playlist:37i9dQZF1DX0XUsuxWHRQd" sourceAccount="username" isPresetable="true">
<itemName>My Worship Mix</itemName>
<containerArt>https://i.scdn.co/image/ab67706c0000da84820d2514932c9e2ea40f6473</containerArt>
</ContentItem>
</preset>
</presets>
</presetsUpdated>
</updates>
```
## CLI Command Updates
The CLI now automatically shows location details for **all sources** when using `play now`:
### Automatic Location Display
```bash
# Location automatically shown for any source with location data
go run ./cmd/soundtouch-cli --host 192.168.1.100 play now
```
**Example outputs:**
**TUNEIN Radio:**
```
Now Playing:
Source: TUNEIN
Track: K-LOVE Radio
Content Details:
Location: /v1/playbook/station/s33828
```
**LOCAL_INTERNET_RADIO:**
```
Now Playing:
Source: LOCAL_INTERNET_RADIO
Track: Custom Radio Station
Content Details:
Location: https://stream.example.com/radio
```
**STORED_MUSIC (NAS):**
```
Now Playing:
Source: STORED_MUSIC
Track: Welcome Home
Artist: MercyMe
Content Details:
Location: 6_a2874b5d_4f83d999
```
### Verbose Mode for Complete Details
```bash
go run ./cmd/soundtouch-cli --host 192.168.1.100 play now --verbose
```
Shows additional information:
```
Content Details:
Location: /v1/playbook/station/s33828
Content Type: stationurl
Item Name: K-LOVE Radio
Presetable: true
```
## Use Cases
1. **Quick Access to Favorite Playlists**: Store frequently used Spotify playlists as presets 1-6
2. **Radio Station Shortcuts**: Save favorite TUNEIN and internet radio stations for instant access
3. **NAS Music Collections**: Store favorite albums from your network storage as presets
4. **Pandora Stations**: Save your custom Pandora radio stations for quick access
5. **Mood-based Presets**: Organize content by activity (workout, relaxation, work)
6. **Family-friendly Setup**: Each family member gets their own preset slots
7. **Smart Home Integration**: Trigger specific music for different scenarios
## Spotify URI Reference
## Location Reference for All Sources
| Source | Location Format | Example |
|--------|-----------------|---------|
| **Spotify Playlist** | `spotify:playlist:ID` | `spotify:playlist:37i9dQZF1DX0XUsuxWHRQd` |
| **Spotify Album** | `spotify:album:ID` | `spotify:album:4aawyAB9vmqN3uQ7FjRGTy` |
| **Spotify Artist** | `spotify:artist:ID` | `spotify:artist:6APm8EjxOHSYM5B4i3vT3q` |
| **Spotify Track** | `spotify:track:ID` | `spotify:track:17GmwQ9Q3MTAz05OokmNNB` |
| **TUNEIN Radio** | `/v1/playbook/station/ID` | `/v1/playbook/station/s33828` |
| **Internet Radio** | `URL or encoded URL` | `https://stream.example.com/radio` |
| **STORED_MUSIC** | `Container ID` | `6_a2874b5d_4f83d999` |
| **LOCAL_MUSIC** | `album:ID` or `track:ID` | `album:983`, `track:2579` |
| **PANDORA Station** | `Station ID` | `126740707481236361` |
## Conclusion
The `/storePreset` feature is **highly feasible** and would add significant value to the SoundTouch API client. The existing infrastructure provides a solid foundation, and the implementation would be straightforward.
Key benefits:
- ✅ **User-friendly**: Simple CLI commands for preset management with automatic location detection
- ✅ **Universal**: Supports ALL content sources (Spotify, TUNEIN, Internet Radio, NAS Music, Pandora, Local Music)
- ✅ **Well-documented**: Complete API specification available
- ✅ **Event-driven**: WebSocket integration for real-time updates
- ✅ **Low complexity**: Leverages existing code patterns and infrastructure
- ✅ **Enhanced CLI**: Automatic location display makes it easy to capture preset data
This feature would enable SoundTouch users to fully utilize their device's preset capabilities programmatically, making it easier to manage and access their favorite content from any supported source.