Skip to main content

SonosSystem

Struct SonosSystem 

Source
pub struct SonosSystem { /* private fields */ }
Expand description

Main system entry point - provides DOM-like API

SonosSystem is fully synchronous - no async/await required.

§Example

use sonos_sdk::SonosSystem;

fn main() -> Result<(), sonos_sdk::SdkError> {
    let system = SonosSystem::new()?;

    // Get speaker by name
    let speaker = system.speaker("Living Room")
        .ok_or_else(|| sonos_sdk::SdkError::SpeakerNotFound("Living Room".to_string()))?;

    // Three methods on each property:
    let volume = speaker.volume.get();              // Get cached value
    let fresh_volume = speaker.volume.fetch()?;     // API call + update cache
    let current = speaker.volume.watch()?;          // Start watching for changes

    // Iterate over changes
    for event in system.iter() {
        println!("Property changed: {:?}", event);
    }

    Ok(())
}

Implementations§

Source§

impl SonosSystem

Source

pub fn new() -> Result<Self, SdkError>

Create a new SonosSystem with cache-first device discovery (sync)

Discovery strategy:

  1. Try loading cached devices from disk (~/.cache/sonos/cache.json)
  2. If cache is fresh (< 24h), use cached devices
  3. If cache is stale, run SSDP; fall back to stale cache if SSDP finds nothing
  4. If no cache exists, run SSDP discovery
  5. If no devices found anywhere, return Err(SdkError::DiscoveryFailed)
Source

pub fn speaker(&self, name: &str) -> Option<Speaker>

Get speaker by name (sync)

If the speaker isn’t in the current map, triggers an SSDP rediscovery (rate-limited to once per 30s) before returning None.

§Example
let kitchen = sonos.speaker("Kitchen").unwrap();
kitchen.play()?;
Source

pub fn get_speaker_by_name(&self, name: &str) -> Option<Speaker>

👎Deprecated since 0.2.0:

renamed to speaker()

Get speaker by name (sync)

Source

pub fn speakers(&self) -> Vec<Speaker>

Get all speakers (sync)

Source

pub fn speaker_by_id(&self, speaker_id: &SpeakerId) -> Option<Speaker>

Get speaker by ID (sync)

Source

pub fn get_speaker_by_id(&self, speaker_id: &SpeakerId) -> Option<Speaker>

👎Deprecated since 0.2.0:

renamed to speaker_by_id()

Get speaker by ID (sync)

Source

pub fn speaker_names(&self) -> Vec<String>

Get all speaker names (sync)

Source

pub fn state_manager(&self) -> &Arc<StateManager>

Get the state manager for advanced usage

Source

pub fn iter(&self) -> ChangeIterator

Get a blocking iterator over property change events

Only emits events for properties that have been watch()ed.

§Example
// First, watch some properties
speaker.volume.watch()?;
speaker.playback_state.watch()?;

// Then iterate over changes (blocking)
for event in system.iter() {
    println!("Changed: {} on {}", event.property_key, event.speaker_id);
}
Source

pub fn groups(&self) -> Vec<Group>

Get all current groups (sync)

Returns all groups in the system. Every speaker is always in a group, so a single speaker forms a group of one.

§Example
for group in system.groups() {
    println!("Group: {} ({} members)", group.id, group.member_count());
    if let Some(coordinator) = group.coordinator() {
        println!("  Coordinator: {}", coordinator.name);
    }
}
Source

pub fn group_by_id(&self, group_id: &GroupId) -> Option<Group>

Get a specific group by ID (sync)

Returns None if no group with that ID exists.

§Example
if let Some(group) = system.group_by_id(&group_id) {
    println!("Found group with {} members", group.member_count());
}
Source

pub fn get_group_by_id(&self, group_id: &GroupId) -> Option<Group>

👎Deprecated since 0.2.0:

renamed to group_by_id()

Get a specific group by ID (sync)

Source

pub fn group_for_speaker(&self, speaker_id: &SpeakerId) -> Option<Group>

Get the group a speaker belongs to (sync)

Returns None if the speaker is not found or has no group. Since all speakers are always in a group, this typically only returns None if the speaker ID is invalid.

§Example
if let Some(speaker) = system.speaker("Living Room") {
    if let Some(group) = system.group_for_speaker(&speaker.id) {
        println!("{} is in a group with {} speakers",
            speaker.name, group.member_count());
    }
}
Source

pub fn get_group_for_speaker(&self, speaker_id: &SpeakerId) -> Option<Group>

👎Deprecated since 0.2.0:

use speaker.group() or group_for_speaker() instead

Get the group a speaker belongs to (sync)

Source

pub fn group(&self, name: &str) -> Option<Group>

Get a group by its coordinator speaker name (sync)

Sonos groups don’t have independent names — they are identified by the coordinator speaker’s friendly name. This method matches groups by looking up the coordinator’s name in the state manager.

Returns None if no group’s coordinator matches the given name.

§Example
if let Some(group) = system.group("Living Room") {
    println!("Found group with {} members", group.member_count());
}
Source

pub fn get_group_by_name(&self, name: &str) -> Option<Group>

👎Deprecated since 0.2.0:

renamed to group()

Get a group by its coordinator speaker name (sync)

Source

pub fn create_group( &self, coordinator: &Speaker, members: &[&Speaker], ) -> Result<GroupChangeResult, SdkError>

Create a new group with the specified coordinator and members

Adds each member speaker to the coordinator’s current group. Attempts every speaker even if some fail, returning per-speaker results. After calling this, re-fetch groups via groups() to see the updated topology.

§Example
let living_room = system.speaker("Living Room").unwrap();
let kitchen = system.speaker("Kitchen").unwrap();
let bedroom = system.speaker("Bedroom").unwrap();

let result = system.create_group(&living_room, &[&kitchen, &bedroom])?;
if !result.is_success() {
    for (id, err) in &result.failed {
        eprintln!("Failed to add {}: {}", id, err);
    }
}

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more