Files
Tobias Gesellchen 2296b3ca9b feat: Implement official /addZoneSlave and /removeZoneSlave endpoints
Implements the remaining zone slave management endpoints from the official
Bose SoundTouch Web API v1.0 specification, bringing API coverage to 89%.

## New Features

### Client Methods
- AddZoneSlave(masterID, slaveID, slaveIP) - Add individual device to zone
- AddZoneSlaveByDeviceID(masterID, slaveID) - Add device by ID only
- RemoveZoneSlave(masterID, slaveID, slaveIP) - Remove individual device
- RemoveZoneSlaveByDeviceID(masterID, slaveID) - Remove device by ID only

### Models
- ZoneSlaveRequest - Request structure for slave operations
- ZoneSlaveEntry - Individual slave entry with IP address support
- Complete XML marshaling/unmarshaling with proper omitempty handling
- Comprehensive validation and error handling

### CLI Commands
- zone add-slave --master ID --slave ID [--slave-ip IP]
- zone remove-slave --master ID --slave ID [--slave-ip IP]

## Implementation Details

- Follows official API specification exactly (POST /addZoneSlave, /removeZoneSlave)
- Supports both device ID + IP and device ID only operations
- Comprehensive input validation (IP addresses, device ID conflicts)
- Proper XML formatting with omitempty for optional IP addresses
- Extensive test coverage (580+ lines of tests)
- Integration with existing high-level zone management API

## Testing

- 200+ new test cases covering all functionality
- Complete model validation and XML marshaling tests
- HTTP client integration tests with mock servers
- Error handling and edge case coverage
- Network error simulation tests

## Documentation Updates

- Updated API coverage from 84% to 89% (17/19 endpoints)
- Comprehensive API coverage analysis document
- Updated README.md with new endpoint status
- Added practical usage examples
- CLI help documentation

## Compatibility

- Maintains full backward compatibility
- Complements existing high-level zone API
- Users can choose between low-level official API or enhanced high-level API
- No breaking changes to existing functionality

This implementation provides both the exact official API endpoints and
enhanced high-level zone management, giving users maximum flexibility
for zone operations while maintaining full API compliance.
2026-01-11 00:10:22 +01:00

94 lines
2.3 KiB
Go

package main
import (
"fmt"
"github.com/urfave/cli/v2"
)
// addZoneSlave adds a device to an existing zone using the official /addZoneSlave endpoint
func addZoneSlave(c *cli.Context) error {
clientConfig := GetClientConfig(c)
masterID := c.String("master")
slaveID := c.String("slave")
slaveIP := c.String("slave-ip")
if masterID == "" {
return fmt.Errorf("master device ID is required (use --master)")
}
if slaveID == "" {
return fmt.Errorf("slave device ID is required (use --slave)")
}
PrintDeviceHeader(fmt.Sprintf("Adding slave '%s' to zone master '%s'", slaveID, masterID), clientConfig.Host, clientConfig.Port)
client, err := CreateSoundTouchClient(clientConfig)
if err != nil {
PrintError(fmt.Sprintf("Failed to create client: %v", err))
return err
}
if slaveIP != "" {
err = client.AddZoneSlave(masterID, slaveID, slaveIP)
} else {
err = client.AddZoneSlaveByDeviceID(masterID, slaveID)
}
if err != nil {
PrintError(fmt.Sprintf("Failed to add zone slave: %v", err))
return err
}
fmt.Printf("✅ Successfully added device '%s' to zone master '%s'\n", slaveID, masterID)
if slaveIP != "" {
fmt.Printf(" Slave IP: %s\n", slaveIP)
}
return nil
}
// removeZoneSlave removes a device from an existing zone using the official /removeZoneSlave endpoint
func removeZoneSlave(c *cli.Context) error {
clientConfig := GetClientConfig(c)
masterID := c.String("master")
slaveID := c.String("slave")
slaveIP := c.String("slave-ip")
if masterID == "" {
return fmt.Errorf("master device ID is required (use --master)")
}
if slaveID == "" {
return fmt.Errorf("slave device ID is required (use --slave)")
}
PrintDeviceHeader(fmt.Sprintf("Removing slave '%s' from zone master '%s'", slaveID, masterID), clientConfig.Host, clientConfig.Port)
client, err := CreateSoundTouchClient(clientConfig)
if err != nil {
PrintError(fmt.Sprintf("Failed to create client: %v", err))
return err
}
if slaveIP != "" {
err = client.RemoveZoneSlave(masterID, slaveID, slaveIP)
} else {
err = client.RemoveZoneSlaveByDeviceID(masterID, slaveID)
}
if err != nil {
PrintError(fmt.Sprintf("Failed to remove zone slave: %v", err))
return err
}
fmt.Printf("✅ Successfully removed device '%s' from zone master '%s'\n", slaveID, masterID)
if slaveIP != "" {
fmt.Printf(" Slave IP: %s\n", slaveIP)
}
return nil
}