sonos-api
A stateless, type-safe Rust library for constructing requests to Sonos speakers and handling their responses.
Overview
The sonos-api crate provides a high-level, stateless layer for interacting with Sonos devices through their UPnP/SOAP interface. It focuses on:
- Request Construction: Type-safe builders for SOAP payloads
- Response Parsing: Structured parsing of XML responses into Rust types
- Operation Modeling: Each UPnP action is modeled as a distinct operation with its own request/response types
- Service Organization: Operations are grouped by UPnP service (AVTransport, RenderingControl, etc.)
This crate is stateless - it doesn't manage connections, maintain device state, or handle networking. It purely focuses on the request/response transformation layer.
Architecture
The crate is built around the SonosOperation trait, which defines a common interface for all Sonos UPnP operations:
Each operation implements this trait to provide:
- Type-safe request and response structures
- SOAP payload construction from request data
- XML response parsing into structured data
Supported Services
The crate currently supports operations for these UPnP services:
- AVTransport: Playback control (play, pause, stop, transport info)
- RenderingControl: Volume and audio settings
- DeviceProperties: Device information and capabilities
- ZoneGroupTopology: Multi-room grouping and topology
- GroupRenderingControl: Group-level audio control
- Events: UPnP event subscriptions (subscribe, unsubscribe, renew) for all services
Usage
Using the SonosClient (Recommended)
The easiest way to use the API is through the SonosClient, which handles all the SOAP communication for you:
use ;
// Create a client
let client = new;
// Create a request
let request = GetTransportInfoRequest ;
// Execute the operation against a device
let response = client.?;
println!;
Working with Different Operations
use ;
let client = new;
let device_ip = "192.168.1.100";
// Play music
let play_request = PlayRequest ;
client.?;
// Get current volume
let volume_request = GetVolumeRequest ;
let volume_response = client.?;
println!;
// Set volume to 50%
let set_volume_request = SetVolumeRequest ;
client.?;
// Pause playback
let pause_request = PauseRequest ;
client.?;
Event Subscriptions
The client also supports UPnP event subscriptions for real-time notifications:
use ;
let client = new;
let device_ip = "192.168.1.100";
// Subscribe to AVTransport events
let subscribe_request = SubscribeRequest ;
let subscription = client.subscribe?;
println!;
// Renew the subscription before it expires
let renew_request = RenewRequest ;
let renewal = client.renew_subscription?;
println!;
// Unsubscribe when done
let unsubscribe_request = UnsubscribeRequest ;
client.unsubscribe?;
Low-Level Operation Usage (Advanced)
For advanced use cases, you can work directly with operations without the client:
use ;
use SonosOperation;
// Create a request
let request = GetTransportInfoRequest ;
// Build the SOAP payload
let payload = build_payload;
// Returns: "<InstanceID>0</InstanceID>"
// Parse a response (after receiving XML from the device)
let xml = /* parsed XML response */;
let response = parse_response?;
println!;
Working with Different Operations
use ;
use ;
// Play operation
let play_request = PlayRequest ;
let play_payload = build_payload;
// Volume operation
let volume_request = GetVolumeRequest ;
let volume_payload = build_payload;
Error Handling
The crate provides structured error handling through the ApiError type:
use ;
let client = new;
let request = GetTransportInfoRequest ;
match client.
Integration with Other Crates
This crate is designed to work with other crates in the Sonos SDK ecosystem:
- soap-client: Handles the actual SOAP communication and networking
- sonos-discovery: Discovers devices on the network
- sonos-stream: Manages event subscriptions and real-time updates
The typical flow is:
- Use
sonos-discoveryto find devices - Use
sonos-apito construct requests and parse responses - Use
soap-clientto send the requests over the network - Use
sonos-streamfor real-time event handling
Design Principles
- Stateless: No connection management or device state tracking
- Type Safety: Strong typing for all requests and responses
- Separation of Concerns: Pure request/response transformation
- Extensible: Easy to add new operations following the same patterns
- Error Transparency: Clear error types for different failure modes
Adding New Operations
To add a new operation:
- Create a new module under the appropriate service directory
- Define request and response types with proper serde annotations
- Implement the
SonosOperationtrait - Add comprehensive tests for payload construction and response parsing
Example structure:
;
Testing
The crate includes comprehensive tests for all operations, covering:
- Payload construction with various input parameters
- Response parsing with valid XML
- Error handling for malformed or missing XML elements
- Edge cases and validation scenarios
Run tests with: