Sonos
GEM driver sonos auto-discovers and controls Sonos speakers (S2 generation) on the LAN over UPnP, using the @svrooij/sonos SSDP library. Each discovered speaker becomes a GEM zone and an AV zone, so the speakers participate in AV routing alongside the rest of the system. The driver covers playback, volume, mute, grouping, queue management, line-in pass-through, music-library browsing and search, and music-service (SMAPI) account linking.
What it does
- One driver instance discovers every Sonos device on the subnet and creates one zone per speaker automatically (
zone.address= the Sonos device UUID, e.g.RINCON_xxxxxx). - Auto-creates an AV zone (
av_type=audio) per speaker so it shows up in AV routing. - Live state via real-time UPnP event subscriptions (volume, mute, transport), with a polling fallback (
status_interval, default 3000 ms) to backfill state when an event is dropped. - Per-zone volume, mute, transport (play/pause/stop/next/previous), shuffle, repeat, crossfade, and sleep timer.
- Speaker grouping (join/leave) using the coordinator looked up from the Sonos zone-group topology.
- Music-library and Sonos-favorites browsing, prefix search, and queue management.
- Music-service (SMAPI) account linking and catalog browse/search — Pandora, SiriusXM, third-party radio, etc. — once the service is authorized on a speaker.
- A dedicated Sonos source view for end users (browse → play/queue, now-playing, presets/favorites). Set the AV source's Component to
sonosto get it — see AV Sources.
Prerequisites
- Sonos speakers already set up through the Sonos app (S2 generation).
- The GEM server on the same VLAN/subnet as the speakers — SSDP multicast does not cross routers. If discovery is blocked, a single seed IP is enough to bootstrap.
Setup steps
Open Devices
- Go to System → Devices → Add Device and create a device with driver
sonos. Leave Seed IP blank to use SSDP multicast discovery, or enter the IP of any one Sonos speaker to seed discovery when multicast is blocked. - Save. The driver discovers the speakers and creates one zone per device automatically, placed under the AV subsystem.
zone.addressis populated with the device UUID — do not set it by hand. (The AV subsystem ships with every install; if it has been deleted, recreate it first or no zones can be created.) - AV zones (
av_type= audio) are auto-created for the speakers so they appear in AV routing right away. To expose Sonos as a selectable source with the rich browse UI, create an AV Source whose Device is this Sonos device and whose Component issonos. Mark it Global if every room should see it.
Attribute reference
Device
| Name | Required | Description |
|---|---|---|
ip | no | Seed IP of any Sonos speaker. Leave blank for SSDP multicast discovery. |
status_interval | no | Status poll interval in ms. Default 3000, min 1000. Backs up the real-time event subscriptions. |
volume_increment | no | Step size for volume_up / volume_down when the zone has no override. Default 2. |
Zone
No required zone attributes — address (the device UUID) is filled in during discovery, never by hand.
The driver writes live speaker state back onto each zone as it changes (from the real-time event subscriptions, backfilled by the status poll). These attribute names are stable, so you can build attribute triggers and bind widgets to them:
| Attribute | Type | Meaning |
|---|---|---|
volume | int | Current volume, 0-100. |
mute_state | string | on / off. |
play_state / playback_state | string | Transport state — PLAYING, PAUSED_PLAYBACK, STOPPED, TRANSITIONING. Both carry the same value. |
input | string | Empty when playing from the local queue; set to the line-in source's UUID when a line input is routed in. |
input_device / input_device_id | string / int | The GEM device feeding the line-in, when the source is another Sonos speaker's line input. |
shuffle | bool | Shuffle on/off. |
repeat_mode | string | none / all / one. |
crossfade | bool | Crossfade on/off. |
route_source / route_mode / route_source_name | string | Set by the input routing command — which speaker is feeding this zone and whether it was joined as line_in or current (grouped). |
is_group_coordinator | bool | True when this speaker leads its group. |
group_coordinator_uuid / group_coordinator_name | string | The coordinator this speaker follows (empty when it is the coordinator / ungrouped). |
group_members | json | Names of the speakers in this speaker's group. |
group_member_count | int | Number of speakers in the group. |
Track/artist/album metadata is not written to the zone — it lives on the AV source's device (see Now-playing metadata). Older builds wrote it to the zone; the driver clears any leftover zone copies on connect.
Now-playing metadata
Now-playing fields (track, artist, album, album_art, repeat_mode, shuffle, plus play_state / playback_state) are written to the AV source's device, not to the zone — this is how the source view and any now-playing widgets pick up metadata. The link is the AV Source's Device field; without it, the source view shows transport controls but no track info. A grouped (follower) speaker originates nothing, so its now-playing metadata is cleared while it follows a coordinator. (Earlier versions wrote these to the zone; the driver clears any leftover zone copies on connect.)
Music services (SMAPI)
Streaming services that the Sonos household already has accounts for can be browsed and played through the speaker's SMAPI bridge:
list_service_accountslists the services available on the speaker with their auth policy and linked status.link_music_servicestarts account linking and returns an authorization URL. Open it, sign in to the service, and approve.complete_service_linkpolls once for completion and, when authorized, saves the account tokens onto the speaker.browse_serviceandsearch_servicethen return the service catalog;play_service_item/queue_service_itemplay or enqueue an item.unlink_music_serviceremoves the saved tokens.
The Sonos source view drives this flow for end users; the commands are also available to macros and the AI assistant.
Some third-party radio services reject the native x-sonosapi-stream URI (UPnP 402) unless the household carries an account serial for them. The driver detects this and falls back to resolving the direct stream URL via SMAPI and playing it as plain internet radio, so the station still plays.
Grouping
join_group (with the target zone_id) makes a speaker join another speaker's group; the driver resolves the coordinator from the zone-group topology, so you pass the GEM zone, not a raw Sonos coordinator name. leave_group removes a speaker from its group.
Commands
| Name | Args | Notes |
|---|---|---|
get_devices | — | List discovered speakers with model/UUID/host. |
volume | address, volume | Set absolute volume 0-100. |
volume_up / volume_down | address | Step volume by volume_increment. |
mute_on / mute_off | address | Mute control. |
get_volume / get_mute / get_input / get_state | address | Refresh a single facet of zone state. |
play / pause / stop / next / previous | address | Transport. |
zone_off | address | Stop and clear the zone. |
input | address, source_address, mode | Route another speaker into this zone. mode is line_in (default — stream that speaker's physical line input) or current (join its current playback). source_address is the source speaker's UUID. |
line_in | address | Switch the zone to its line-in input. |
switch_to_queue | address | Switch playback back to the local queue. |
join_group / leave_group | address (+ zone_id to join) | Group speakers. |
set_shuffle / set_repeat | address, shuffle / repeat | Set play modes. |
shuffle_toggle | address | Toggle shuffle, preserving repeat. |
repeat_toggle | address | Cycle repeat none/all/one, preserving shuffle. |
set_crossfade | address, crossfade | Enable/disable crossfade. |
set_sleep_timer | address, duration | Sleep timer (HH:MM:SS). |
get_queue / clear_queue | address | Read or clear the queue. |
play_queue_track | address, track_nr | Jump to a 1-based queue position and play. |
get_position | address | Current track position and duration. |
browse_content | address, object_id, start_index, count | Browse the library with custom parameters. |
browse_artists / browse_albums / browse_genres / browse_playlists / browse_favorites | address | Browse a library category or Sonos favorites. |
find_prefix | address, container_id, prefix | Jump to entries starting with a prefix. |
refresh_library | address | Re-index the music library. |
get_search_capabilities / get_sort_capabilities | address | Report what the library supports. |
play_item / queue_item | address, uri (+ next to queue) | Play or enqueue a browsed item. Pass the browsed object as args.item for correct metadata. |
play_favorite | address, item_id | Play a Sonos favorite by id (FV:2/n). |
list_music_services / update_music_services | address | List/refresh the services on the speaker. |
get_music_session | address, service_id, username | Return the speaker's session id for a music service (low-level SMAPI session lookup). |
list_service_accounts | address | Services with auth policy and linked status. |
link_music_service | address, service_id | Begin account linking; returns the authorization URL. |
complete_service_link | address, service_id | Poll once for link completion; saves tokens. |
unlink_music_service | address, service_id | Remove saved account tokens. |
browse_service | address, service_id, item_id, start_index, count | Browse a service catalog (item_id defaults to root). |
search_service | address, service_id, term, category | Search a service catalog. |
play_service_item / queue_service_item | address, service_id, item_id (+ next) | Play or enqueue a service item. |
Known limitations
- Discovery requires multicast on the local subnet; firewalls or VLAN isolation hide speakers. Provide a seed IP if discovery fails.
- Zones are addressed by Sonos device UUID, populated during discovery — never enter the address manually.
- Music-service browsing depends on the account already existing in the Sonos household; GEM links the speaker to it, it does not create the streaming account.
Troubleshooting
| Symptom | Check |
|---|---|
| No zones created on connect. | SSDP multicast is being blocked. Enter a Seed IP of any known Sonos speaker on the device row. |
| Group commands fail with "invalid zone". | The target zone is in a different fabric or was removed from the Sonos system; reload the device or re-run discovery. |
| Volume/mute not updating in real time. | The UPnP event subscription dropped; the polling fallback (status_interval) catches up, and a full re-subscribe happens on the next driver reload. |
| Source view shows controls but no track info. | The AV Source has no Device set, or the device is not this Sonos driver — now-playing metadata is written to the source's device. |
| A radio station won't start. | The service may need an account serial; the driver falls back to plain internet radio, but a station with no resolvable stream URL cannot play. |