Documentation for controlling and preserving Bose SoundTouch devices
This document describes the implementation of the POST /key endpoint for media control commands in the Bose SoundTouch API client.
The key control functionality allows sending media control commands to SoundTouch devices, including play/pause, volume adjustment, track navigation, and preset selection.
pkg/models/key.go - XML model and constants for key commandspkg/models/key_test.go - Comprehensive tests for key functionalitypkg/client/client.go - Client methods for sending key commandscmd/soundtouch-cli/main.go - CLI commands for key controlsSends a key command to the SoundTouch device.
Request Format: According to the API documentation, proper key simulation requires sending both press and release states:
<key state="press" sender="Gabbo">KEY_NAME</key>
<key state="release" sender="Gabbo">KEY_NAME</key>
Response Format:
<?xml version="1.0" encoding="UTF-8" ?>
<status>/key</status>
During implementation, we discovered that the sender attribute is critical for successful key commands. Only specific sender values are accepted:
Our implementation uses “Gabbo” as the default sender, which is the standard value used in official SoundTouch examples.
PLAY - Start playbackPAUSE - Pause current playbackSTOP - Stop current playbackPREV_TRACK - Go to previous trackNEXT_TRACK - Go to next trackTHUMBS_UP - Rate current content positively (Pandora, etc.)THUMBS_DOWN - Rate current content negativelyBOOKMARK - Bookmark current contentPOWER - Toggle device power stateMUTE - Toggle mute stateVOLUME_UP - Increase volumeVOLUME_DOWN - Decrease volumePRESET_1 through PRESET_6 - Select preset 1-6AUX_INPUT - Switch to auxiliary inputSHUFFLE_OFF - Turn shuffle mode offSHUFFLE_ON - Turn shuffle mode onREPEAT_OFF - Turn repeat mode offREPEAT_ONE - Repeat current trackREPEAT_ALL - Repeat all tracks in playlist// Send complete key command (press + release - recommended)
err := client.SendKey(models.KeyPlay)
// Send key press and release (alias for SendKey)
err := client.SendKeyPress(models.KeyPlay)
// Send only key press state (advanced usage)
err := client.SendKeyPressOnly(models.KeyPlay)
// Send only key release state (advanced usage)
err := client.SendKeyReleaseOnly(models.KeyPlay)
// Media controls
err := client.Play()
err := client.Pause()
err := client.Stop()
err := client.NextTrack()
err := client.PrevTrack()
// Volume controls
err := client.VolumeUp()
err := client.VolumeDown()
// Preset selection (1-6)
err := client.SelectPreset(1)
// Check if a key value is valid
isValid := models.IsValidKey("PLAY") // true
isValid := models.IsValidKey("INVALID") // false
// Get all valid key values
allKeys := models.GetAllValidKeys()
# Media controls
soundtouch-cli -host 192.168.1.100 -play
soundtouch-cli -host 192.168.1.100 -pause
soundtouch-cli -host 192.168.1.100 -stop
soundtouch-cli -host 192.168.1.100 -next
soundtouch-cli -host 192.168.1.100 -prev
# Volume controls
soundtouch-cli -host 192.168.1.100 -volume-up
soundtouch-cli -host 192.168.1.100 -volume-down
# Preset selection
soundtouch-cli -host 192.168.1.100 -preset 1
soundtouch-cli -host 192.168.1.100 -preset 6
# Send any valid key using the -key flag
soundtouch-cli -host 192.168.1.100 -key PLAY
soundtouch-cli -host 192.168.1.100 -key STOP
soundtouch-cli -host 192.168.1.100 -key PRESET_3
# Invalid key validation
$ soundtouch-cli -host 192.168.1.100 -key INVALID
Failed to send key command: invalid key value: INVALID
# Multiple commands rejected
$ soundtouch-cli -host 192.168.1.100 -play -pause
Failed to send key command: only one key command can be sent at a time
# Missing host
$ soundtouch-cli -play
Host is required for key commands. Use -host flag or -discover to find devices.
The implementation includes comprehensive unit tests in pkg/models/key_test.go:
Run tests:
go test ./pkg/models/...
Tested with real SoundTouch devices:
All key commands successfully sent and executed on both devices.
package main
import (
"log"
"github.com/gesellix/bose-soundtouch/pkg/client"
"github.com/gesellix/bose-soundtouch/pkg/models"
)
func main() {
// Create client
soundtouchClient := client.NewClientFromHost("192.168.1.100")
// Play music
if err := soundtouchClient.Play(); err != nil {
log.Fatalf("Failed to play: %v", err)
}
// Adjust volume
if err := soundtouchClient.VolumeUp(); err != nil {
log.Fatalf("Failed to increase volume: %v", err)
}
// Select preset
if err := soundtouchClient.SelectPreset(1); err != nil {
log.Fatalf("Failed to select preset: %v", err)
}
}
func sendKeyCommand(client *client.Client, keyValue string) error {
// Validate before sending
if !models.IsValidKey(keyValue) {
return fmt.Errorf("invalid key: %s", keyValue)
}
// SendKey automatically sends both press and release states
return client.SendKey(keyValue)
}
func sendAllValidKeys(client *client.Client) {
for _, key := range models.GetAllValidKeys() {
fmt.Printf("Sending key: %s (press+release)\n", key)
if err := client.SendKey(key); err != nil {
log.Printf("Failed to send %s: %v", key, err)
}
time.Sleep(1 * time.Second) // Avoid overwhelming the device
}
}
SendKey() sends both press and release states for proper key simulationsender attribute must be “Gabbo” for commands to be acceptedPotential areas for future development: