Skip to main content

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 sonos to 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

  1. 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.
  2. Save. The driver discovers the speakers and creates one zone per device automatically, placed under the AV subsystem. zone.address is 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.)
  3. 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 is sonos. Mark it Global if every room should see it.

Attribute reference

Device

NameRequiredDescription
ipnoSeed IP of any Sonos speaker. Leave blank for SSDP multicast discovery.
status_intervalnoStatus poll interval in ms. Default 3000, min 1000. Backs up the real-time event subscriptions.
volume_incrementnoStep 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:

AttributeTypeMeaning
volumeintCurrent volume, 0-100.
mute_statestringon / off.
play_state / playback_statestringTransport state — PLAYING, PAUSED_PLAYBACK, STOPPED, TRANSITIONING. Both carry the same value.
inputstringEmpty 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_idstring / intThe GEM device feeding the line-in, when the source is another Sonos speaker's line input.
shuffleboolShuffle on/off.
repeat_modestringnone / all / one.
crossfadeboolCrossfade on/off.
route_source / route_mode / route_source_namestringSet by the input routing command — which speaker is feeding this zone and whether it was joined as line_in or current (grouped).
is_group_coordinatorboolTrue when this speaker leads its group.
group_coordinator_uuid / group_coordinator_namestringThe coordinator this speaker follows (empty when it is the coordinator / ungrouped).
group_membersjsonNames of the speakers in this speaker's group.
group_member_countintNumber 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:

  1. list_service_accounts lists the services available on the speaker with their auth policy and linked status.
  2. link_music_service starts account linking and returns an authorization URL. Open it, sign in to the service, and approve.
  3. complete_service_link polls once for completion and, when authorized, saves the account tokens onto the speaker.
  4. browse_service and search_service then return the service catalog; play_service_item / queue_service_item play or enqueue an item.
  5. unlink_music_service removes the saved tokens.

The Sonos source view drives this flow for end users; the commands are also available to macros and the AI assistant.

Radio stream fallback

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

NameArgsNotes
get_devicesList discovered speakers with model/UUID/host.
volumeaddress, volumeSet absolute volume 0-100.
volume_up / volume_downaddressStep volume by volume_increment.
mute_on / mute_offaddressMute control.
get_volume / get_mute / get_input / get_stateaddressRefresh a single facet of zone state.
play / pause / stop / next / previousaddressTransport.
zone_offaddressStop and clear the zone.
inputaddress, source_address, modeRoute 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_inaddressSwitch the zone to its line-in input.
switch_to_queueaddressSwitch playback back to the local queue.
join_group / leave_groupaddress (+ zone_id to join)Group speakers.
set_shuffle / set_repeataddress, shuffle / repeatSet play modes.
shuffle_toggleaddressToggle shuffle, preserving repeat.
repeat_toggleaddressCycle repeat none/all/one, preserving shuffle.
set_crossfadeaddress, crossfadeEnable/disable crossfade.
set_sleep_timeraddress, durationSleep timer (HH:MM:SS).
get_queue / clear_queueaddressRead or clear the queue.
play_queue_trackaddress, track_nrJump to a 1-based queue position and play.
get_positionaddressCurrent track position and duration.
browse_contentaddress, object_id, start_index, countBrowse the library with custom parameters.
browse_artists / browse_albums / browse_genres / browse_playlists / browse_favoritesaddressBrowse a library category or Sonos favorites.
find_prefixaddress, container_id, prefixJump to entries starting with a prefix.
refresh_libraryaddressRe-index the music library.
get_search_capabilities / get_sort_capabilitiesaddressReport what the library supports.
play_item / queue_itemaddress, uri (+ next to queue)Play or enqueue a browsed item. Pass the browsed object as args.item for correct metadata.
play_favoriteaddress, item_idPlay a Sonos favorite by id (FV:2/n).
list_music_services / update_music_servicesaddressList/refresh the services on the speaker.
get_music_sessionaddress, service_id, usernameReturn the speaker's session id for a music service (low-level SMAPI session lookup).
list_service_accountsaddressServices with auth policy and linked status.
link_music_serviceaddress, service_idBegin account linking; returns the authorization URL.
complete_service_linkaddress, service_idPoll once for link completion; saves tokens.
unlink_music_serviceaddress, service_idRemove saved account tokens.
browse_serviceaddress, service_id, item_id, start_index, countBrowse a service catalog (item_id defaults to root).
search_serviceaddress, service_id, term, categorySearch a service catalog.
play_service_item / queue_service_itemaddress, 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

SymptomCheck
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.