README
¶
🔊 sonoscli — Discover, group, and control Sonos
sonoscli is a modern Go CLI to control Sonos speakers over your local network (UPnP/SOAP).
Features
- Reliable discovery: SSDP + topology (
ZoneGroupTopology.GetZoneGroupState) with subnet scan fallback. - Coordinator-aware control: target any room; commands go to the group coordinator automatically.
- Playback controls: play/pause/stop/next/prev, plus
play-uri,linein, andtv. - Grouping: inspect groups, join/unjoin, party mode, dissolve groups, and solo a room.
- Queue: list/play/remove/clear queue entries.
- Favorites: list and play Sonos Favorites by index or title.
- Scenes: save/apply presets (grouping + per-room volume/mute).
- Spotify:
- Enqueue/play Spotify share links or canonical
spotify:<type>:<id>URIs (no Spotify credentials required). - Search Spotify via SMAPI (Sonos Music API; uses your linked service in Sonos).
- Optional Spotify Web API search (client credentials) if you want it.
- Enqueue/play Spotify share links or canonical
- Live events:
watchsubscribes to AVTransport + RenderingControl and prints changes. - Scriptable output:
--format plain|json|tsvplus--debugtracing.
This is not an official Sonos project.
Requirements
- Your machine must be on the same network as your Sonos system.
- Speakers must be reachable on TCP port
1400(e.g.http://<speaker-ip>:1400/).
Spotify:
- Spotify must already be linked in the Sonos app.
- This CLI does not authenticate with Spotify; it enqueues Sonos “Spotify” URIs/metadata.
Spotify search (recommended, no Spotify Web API credentials):
sonos smapi searchuses Sonos SMAPI to search linked services (e.g. Spotify).- Some services require a one-time DeviceLink/AppLink flow:
sonos auth smapi begin|complete.
Spotify search via Spotify Web API (optional):
- If you want
sonos search spotify, you’ll need a Spotify Web API app (client credentials). SetSPOTIFY_CLIENT_IDandSPOTIFY_CLIENT_SECRET(or pass--client-id/--client-secret).
Install / build
Install (Homebrew, single line):
brew install steipete/tap/sonoscli
This installs the sonos binary.
Upgrade later:
brew upgrade steipete/tap/sonoscli
Install from source (Go):
go install github.com/STop211650/sonoscli/cmd/sonos@latest
sonos --version
Build a local binary:
go build -o sonos ./cmd/sonos
./sonos --version
./sonos --help
Quick start
Note: if you installed via Homebrew or go install, replace ./sonos with sonos.
Discover speakers:
./sonos discover
./sonos discover --format json
./sonos discover --all # include invisible/bonded devices (advanced)
Show status (text or JSON):
./sonos status --name "Kitchen"
./sonos now --name "Kitchen"
./sonos status --name "Kitchen" --format json
Playback:
./sonos play --name "Kitchen"
./sonos pause --name "Kitchen"
./sonos stop --name "Kitchen"
./sonos next --name "Kitchen"
./sonos prev --name "Kitchen"
Watch live events (track/volume changes):
./sonos watch --name "Kitchen"
./sonos watch --name "Kitchen" --format json
./sonos watch --name "Kitchen" --format tsv
Note: this starts a local callback server for UPnP events; your OS firewall may prompt to allow incoming connections.
Command overview
Run sonos --help for the full list. Most commonly used:
- Discovery & status:
discover,status/now,watch - Playback:
play,pause,stop,next,prev,open,enqueue,play-uri,linein,tv - Grouping:
group status,group join,group unjoin,group solo,group party,group dissolve - Queue:
queue list,queue play,queue remove,queue clear - Favorites:
favorites list,favorites open - Scenes:
scene save,scene apply,scene list,scene delete - Spotify search:
smapi search(recommended), optionalsearch spotify(Spotify Web API)
Queue
List the queue:
./sonos queue list --name "Kitchen"
./sonos queue list --name "Kitchen" --format json
Play or remove a queue entry (positions are 1-based):
./sonos queue play --name "Kitchen" 1
./sonos queue remove --name "Kitchen" 3
Clear the queue:
./sonos queue clear --name "Kitchen"
Scenes (presets)
Save a scene (grouping + per-room volume/mute):
./sonos scene save "Evening"
Apply a scene later:
./sonos scene apply "Evening"
List / delete scenes:
./sonos scene list
./sonos scene delete "Evening"
Scenes are stored in your user config dir as sonoscli/scenes.json (e.g. ~/.config/sonoscli/scenes.json on macOS/Linux).
Favorites
List Sonos Favorites:
./sonos favorites list --name "Kitchen"
./sonos favorites list --name "Kitchen" --format json
Play by index (from the list):
./sonos favorites open --name "Kitchen" --index 1
Or play by title (case-insensitive exact match):
./sonos favorites open --name "Kitchen" "BBC Radio 6 Music"
Other sources
Play an arbitrary URI:
./sonos play-uri --name "Kitchen" "https://example.com/stream.mp3"
Force radio-style playback (useful for station-like streams):
./sonos play-uri --name "Kitchen" --radio --title "My Stream" "https://example.com/live.mp3"
Switch to line-in (optionally from another speaker):
./sonos linein --name "Kitchen" --from "Living Room"
Switch to TV input (soundbar):
./sonos tv --name "Living Room"
Grouping
Show current groups:
./sonos group status
./sonos group status --all # include invisible/bonded devices (advanced)
Join Bedroom into Living Room’s group:
./sonos group join --name "Bedroom" --to "Living Room"
Room targeting supports fuzzy substring matching (and will suggest matches on ambiguity):
./sonos group join --name "Off" --to "Bar" # "Office" joins "Bar"
./sonos group join --name "Bed" --to "Liv" # "Bedroom" joins "Living Room"
Ungroup a speaker (make it standalone):
./sonos group unjoin --name "Bedroom"
Solo a speaker (ungroup its current group so it plays alone):
./sonos group solo --name "Office"
Party mode (join all visible speakers to a target group):
./sonos group party --to "Bar"
Dissolve a group (ungroup all members of the group):
./sonos group dissolve --name "Living Room"
Ungroup Office and play on Office only:
./sonos group solo --name "Office"
./sonos open --name "Office" "https://open.spotify.com/album/<id>"
Re-join a speaker back into another group:
./sonos group join --name "Office" --to "Bar"
Group volume / mute (affects the whole group):
./sonos group volume get --name "Living Room"
./sonos group volume set --name "Living Room" 25
./sonos group mute get --name "Living Room"
./sonos group mute toggle --name "Living Room"
Volume / mute:
./sonos volume get --name "Kitchen"
./sonos volume set --name "Kitchen" 25
./sonos mute get --name "Kitchen"
./sonos mute toggle --name "Kitchen"
Targeting and groups
Target a speaker by:
--name "Kitchen"(Sonos room name)--ip 192.168.0.250(speaker IP)
Most commands must be sent to the group coordinator (the device that owns transport state for the group). sonoscli resolves the coordinator automatically so commands behave like the Sonos app.
Spotify
Search via Sonos (SMAPI; no Spotify Web API credentials):
./sonos smapi services
./sonos smapi categories --service "Spotify"
./sonos smapi browse --service "Spotify" --id root
./sonos auth smapi begin --service "Spotify"
# open the printed URL in a browser, link your account, then:
./sonos auth smapi complete --service "Spotify" --code <linkCode> --wait 5m
./sonos smapi search --service "Spotify" --category tracks "gareth emery"
./sonos smapi search --service "Spotify" --category tracks --open --name "Office" "gareth emery"
Play from a search query (shortcut for SMAPI search + open):
./sonos play spotify --name "Office" "gareth emery"
./sonos play spotify --name "Office" --category albums "gareth emery"
SMAPI tokens are stored under your user config dir as sonoscli/smapi_tokens.json (e.g. ~/.config/sonoscli/smapi_tokens.json on macOS/Linux).
Search via Spotify Web API (prints playable URIs):
export SPOTIFY_CLIENT_ID="..."
export SPOTIFY_CLIENT_SECRET="..."
./sonos search spotify --type track --limit 5 "daft punk harder better"
./sonos search spotify --type playlist "focus"
Open the first search result directly on Sonos:
./sonos search spotify --open --name "Kitchen" "miles davis so what"
Enqueue + play:
./sonos open --name "Kitchen" spotify:track:6NmXV4o6bmp704aPGyTVVG
./sonos open --name "Kitchen" https://open.spotify.com/track/6NmXV4o6bmp704aPGyTVVG
Enqueue only:
./sonos enqueue --name "Kitchen" spotify:playlist:37i9dQZF1DXcBWIGoYBM5M
Notes:
- The enqueue implementation tries Spotify Sonos service numbers
2311and3079for compatibility. - Use
--titleto override the queue display title for some entries.
Dev workflow
Makefile
make fmt
make test
make build
make lint
make lint requires golangci-lint:
brew install golangci-lint
# or:
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
pnpm helper scripts
This repo includes a minimal package.json so you can drive the workflow with pnpm (no Node dependencies required):
pnpm build
pnpm test
pnpm format
pnpm lint
pnpm sonos -- discover
pnpm sonos -- status --name "Kitchen"
pnpm sonos -- open --name "Kitchen" spotify:track:6NmXV4o6bmp704aPGyTVVG
pnpm sonos -- search spotify "miles davis so what"
pnpm sonos -- group status
pnpm sonos -- queue list --name "Kitchen"
CI runs: gofmt check, go vet, go test, and golangci-lint.
Global flags
--ip <ip>: target by IP--name <name>: target by speaker name (defaults tosonos config defaultRoomif set)--timeout <duration>: discovery/network timeout (default5s)--format plain|json|tsv: output format (defaults tosonos config formatif set)--json: deprecated alias for--format json--debug: enable detailed trace logs (SSDP/topology/SOAP timings)
Config (defaults)
Persist small local defaults:
./sonos config get
./sonos config set defaultRoom "Office"
./sonos config set format json
./sonos config unset defaultRoom
Troubleshooting
discoveris empty:- Some networks block multicast/SSDP;
sonosclifalls back to scanning local /24 subnets for port1400and then uses Sonos topology to list all rooms. - Ensure Wi‑Fi client isolation is off and you’re on the same LAN/subnet.
- Some networks block multicast/SSDP;
- Discovery is slow or flaky:
- Run
sonos --debug discoverto see whether SSDP multicast is timing out and whether topology calls are slow.
- Run
- Discovery / SOAP calls hang or time out on your network:
sonoscliretries local Sonos HTTP/SOAP calls viacurlas a workaround for some network/firmware quirks.
- Commands fail with UPnP/SOAP errors:
- Verify you can reach
http://<speaker-ip>:1400/from this machine. - Try targeting by
--name(it resolves the coordinator).
- Verify you can reach
- Spotify enqueue fails:
- Confirm Spotify is linked and playable in the Sonos app.
- Some systems behave differently per firmware/service configuration.
Inspiration / references
This project was informed by the Sonos control ecosystem and the SoCo Python library:
https://github.com/SoCo/SoCo
Design doc
See docs/spec.md.
License
MIT License. See LICENSE.