Denon HEOS
Control a HEOS whole-home audio network — Denon and Marantz HEOS-enabled speakers and receivers, plus the standalone HEOS components (HEOS Amp, HEOS Link, HEOS Drive) — over the HEOS CLI protocol. One thing to understand up front: a single network connection sees every HEOS player on the LAN. You point this driver at the IP of any one HEOS speaker or amp, and through that one connection you can browse, play, and control all of them. Each player is then addressed by its HEOS player id (the pid).
The driver covers playback transport, volume and mute, queue management, music-source browsing and search, presets, physical inputs, and live push events (now-playing, state changes). It also backs the on-screen HEOS source view that end users see on a touchpanel, with dedicated browse panels for Pandora, SiriusXM, and Amazon Music.
How HEOS addressing works
This is the one concept that makes everything else fall into place:
- The connection is to one HEOS device's IP on TCP port 1255. That device is just the gateway — it relays to the whole HEOS network.
- A player (one speaker, amp, or AVR zone) is identified by its pid — a long numeric id
HEOS assigns, e.g.
1234567890. Almost every command takes aplayer_idargument, and that argument is the pid. - A music source (Pandora, SiriusXM, the local USB/DLNA library, etc.) is identified by a
small numeric source id (
sid). Browse and play-from-service commands take asource_idargument.
You discover the pids with the get_players command (it returns every player's name, model,
and pid) and the source ids with the get_music_sources command. You do not type these by
guessing — you read them off the network.
What's controlled
- Transport: play, pause, stop, next, previous
- Volume: absolute set (
0–100), step up/down, mute on/off/toggle - Now-playing metadata and live play-state push events
- Queue: read, clear, jump to a queue item
- Music-source browsing and search, container (album/playlist) and track playback
- Station/stream playback, favorites presets, and physical input selection
- Direct URL playback (play any reachable stream URL on a player)
Prerequisites
- At least one HEOS-enabled device on the LAN, already set up through the HEOS mobile app.
- The GEM server and the HEOS devices on the same subnet/VLAN — HEOS discovers its own
players over multicast, so a player on a different VLAN won't appear in
get_players. - HEOS account credentials (the same email/password used in the HEOS app). These are only needed for streaming-service browse and playback; local-library and basic transport work without an account, but most installs will want the account signed in.
Setup
There are two ways to deploy this driver. Pick based on what you need.
Pattern A — one gateway device, many players
Best when macros or the AI assistant drive many players from one place, passing the pid each time.
Open Devices
- Go to System → Devices → Add Device and choose the Denon HEOS driver.
- Set HEOS Device IP to the LAN IP of any one HEOS speaker/amp. Leave Port at
1255. - Enter the HEOS Account Username and HEOS Account Password if you want streaming services. The password is stored encrypted.
- Save. On connect the driver signs in to the HEOS account, turns on push-event subscription,
and is ready. Run the
get_playerscommand to list every player and its pid. - From then on, send commands with the target player's pid in the
player_idargument — for example a macro step runningset_volumewithplayer_id= the kitchen speaker's pid andvolume=40.
Pattern B — one device pinned to a single player
Best when you want a player to behave like a normal GEM zone/source — a volume slider, the source view, on/off macros — without supplying the pid on every command.
- Create a HEOS device exactly as in Pattern A (point it at that room's speaker IP).
- Open Attributes for the device and add an attribute named
player_idset to that player's pid. (Optionally addsource_idset to the default music source id you want its source view to open on.) - Save and reload the device. Now every command this device sends automatically targets that one
player — you can leave the
player_idargument off, bind the device as an AV zone's Volume Device, and use the HEOS source view.
player_id attribute mattersVolume, mute, and transport commands address the player by its pid. If a command runs with no
pid — neither passed in its player_id argument nor present as a player_id attribute on the
device — HEOS rejects it because it can't tell which player you mean. Setting the player_id
attribute (Pattern B) fills that in for every command automatically; otherwise (Pattern A) you
must supply it per command.
Using HEOS as an on-screen source
To give a room a HEOS streaming source with the browse / now-playing UI:
- Make sure the source's HEOS device carries a
player_idattribute (the target player's pid) and asource_idattribute (the music source to open on) — see Pattern B. The source view reads both off the device and will warn if either is missing. - Open AV Sources and create a source. Set Device to that HEOS device.
- Set Component to
heosfor the generic HEOS browser, or topandora,siriusxm, oramazon_musicfor a service-specific panel (those panels render their HEOS variant because the source's device uses this driver). - Mark it Global source if every room should be able to pick it. Save.
The source view then shows now-playing (track, artist, album art) and a browse surface for the chosen service, and it tracks live changes via the driver's push events. See AV Sources for the full source editor.
HEOS players are their own audio output — a HEOS source isn't routed through a matrix the way a shared cable box is. So a HEOS source is normally a Global streaming source, and its routing macros (if any) just start playback on the player rather than switching a matrix input.
Music source ids
The exact ids depend on what's enabled on the HEOS account, so always confirm with
get_music_sources. Common HEOS source ids:
| Source | source_id |
|---|---|
| Pandora | 1 |
| SiriusXM | 8 |
| Amazon Music | 13 |
| Local music (USB / DLNA / network library) | (varies — read from get_music_sources) |
Pandora (1) and SiriusXM (8) are confirmed by the dedicated source-view panels; the rest can
shift per account and firmware, which is why get_music_sources is the authority.
Attribute reference
Device
| Attribute | Required | Type | Default | Description |
|---|---|---|---|---|
ip | yes | string | — | LAN IP of any HEOS-enabled speaker/amp (the gateway). |
port | no | int | 1255 | HEOS CLI port. Leave at the default. |
username | no | string | — | HEOS account email. Needed for streaming-service playback. |
password | no | string (encrypted) | — | HEOS account password. Stored encrypted. |
player_id | no | string | — | Pins this device to one player (its pid). Set it to drive that player without passing player_id on every command, and to enable the source view / AV-zone volume binding. |
source_id | no | string | — | Default music source id the source view opens on. |
heos_player_id / heos_source_id are accepted as alternate names for player_id / source_id
if you have older rows using them; prefer the short names on new installs.
Commands
Every command below that names a player_id argument takes the target player's pid (or omit it
when the device has a player_id attribute set — Pattern B).
Discovery and status
| Command | Args | Description |
|---|---|---|
get_players | — | List every HEOS player on the network with name, model, and pid. Start here. |
get_player_info | player_id | Detailed info for one player. |
get_play_state | player_id | Current transport state. |
get_now_playing | player_id | Current track/station metadata. |
get_volume | player_id | Current volume. |
get_mute_status | player_id | Current mute state. |
get_play_mode | player_id | Shuffle / repeat mode. |
get_music_sources | — | List available music sources with their source ids. |
get_source_info | source_id | Detail for one music source. |
get_search_criteria | source_id | Search fields a source supports (get_source_search_criteria is an alias). |
Transport
| Command | Args | Description |
|---|---|---|
play | player_id | Resume / start playback. |
pause | player_id | Pause. |
stop | player_id | Stop. |
next | player_id | Skip to next track. |
previous | player_id | Previous track. |
set_play_state | state, player_id | Set transport directly (play / pause / stop). |
Volume and mute
| Command | Args | Description |
|---|---|---|
set_volume | player_id, volume | Absolute volume 0–100. |
volume_up | player_id, step_amount | Raise volume by step_amount. |
volume_down | player_id, step_amount | Lower volume by step_amount. |
mute_on | player_id | Mute. |
mute_off | player_id | Unmute. |
mute_toggle | player_id | Toggle mute. |
Browse, search, and play
| Command | Args | Description |
|---|---|---|
browse_source | source_id, start, end | Browse a music source's top level over a result range. |
browse_source_container | source_id, container_id, start, end | Browse inside a container (album, playlist, genre) by its cid. |
search | source_id, search, criteria, start, end | Search a source; criteria is a search-criteria id from get_search_criteria. |
play_container | source_id, player_id, container_id | Replace the queue with a container and play. |
play_track | player_id, source_id, container_id, media_id | Replace the queue with one track (its mid) and play. |
play_station | player_id, source_id, container_id, media_id, station_name | Play a station / radio stream. |
play_url | player_id, url | Play any reachable stream URL on the player. |
play_input | input_name, player_id | Switch the player to a physical input (e.g. an aux_in / line input). |
play_preset | player_id, preset_position | Play a saved HEOS favorite by its 1-based preset slot. |
set_service_option | source_id, option, media_id | Apply a service option (thumbs-up, add-to-favorites, etc.). |
Queue
| Command | Args | Description |
|---|---|---|
get_queue | player_id, start, end | Read the play queue over a range. |
queue_container | source_id, player_id, container_id | Add a container to the queue (don't replace). |
queue_track | source_id, player_id, container_id, media_id | Add one track to the queue. |
play_queue_item | player_id, song_id | Jump to and play a queue item by its qid. |
clear_queue | player_id | Empty the queue. |
Account and system
| Command | Args | Description |
|---|---|---|
sign_in | username, password | Sign in to the HEOS account (the driver also does this automatically). |
sign_out | — | Sign out of the HEOS account. |
check_account | — | Report the signed-in account state. |
subscribe_events | enable | Turn push-event subscription on/off (driver enables on connect). |
heartbeat | — | HEOS keepalive ping. |
reboot | — | Reboot the HEOS device. Use with care — it drops the connection until it comes back. |
prettify_json | enable | Toggle pretty-printed responses (diagnostic). |
passthrough | command | Send a raw HEOS CLI path (everything after heos://) — an escape hatch for commands not listed above. |
Behavior and limitations
- One connection, whole network. All players share the single TCP session to the gateway
device. Don't create a second HEOS device pointed at a different speaker just to reach more
players — the one connection already sees them all. (Creating a second device pinned to a
specific player via its
player_idattribute, per Pattern B, is fine and intended.) - Automatic sign-in and event re-arm. On every connect the driver signs in to the HEOS account and re-enables push-event subscription, and it re-signs in roughly once an hour. If a command comes back reporting the account isn't logged in, the driver re-runs sign-in on the spot. So streaming access self-heals after a network blip.
- Push events. Now-playing changes are delivered live (briefly debounced so a burst of metadata updates settles into one). Play-state, queue-change, and now-playing-progress events are received but not all surfaced as separate notifications — the source view re-requests now-playing when it sees a change.
- Auto-reconnect. The connection persists and reconnects automatically with backoff if the gateway speaker drops off the network or reboots.
- No automatic zone discovery. Unlike some multi-room drivers, this one does not create a GEM zone per player on its own. You decide which players become zones/sources and configure them (Pattern B) or drive them by pid (Pattern A).
Troubleshooting
| Symptom | Check |
|---|---|
get_players returns fewer players than you have | The missing players are on a different VLAN/subnet. HEOS discovery is multicast within one subnet — put the GEM host and the speakers on the same network. |
| Volume / transport commands do nothing | The command ran with no pid. Either pass the target player's pid in the player_id argument, or set a player_id attribute on the device (Pattern B). |
| Streaming returns "user not logged in" | The HEOS account username/password is missing or wrong. It's the same login used in the HEOS mobile app. The driver retries sign-in automatically once credentials are correct. |
| No now-playing or live updates | The push subscription didn't arm. Reload the device — the driver re-enables event subscription on every connect. |
| Source view warns about a missing player or source id | The source's HEOS device has no player_id and/or source_id attribute. Add both (Pattern B), then reload. |
| A station won't start | Confirm the source is enabled on the HEOS account and that you're using a current source_id from get_music_sources — service ids can change per account/firmware. |
Related
- Denon Receiver — Denon AVRs over the Telnet control protocol (a HEOS controller connected to the same receiver can lock out that Telnet session, so watch for it).
- Marantz Receiver — the Marantz sibling of the receiver driver.
- Sonos — the other major multi-room audio integration, for comparison of patterns.
- AV Sources — set the Component and Device for the HEOS source view.
- AV Zones — bind a player (Pattern B) as a zone's Volume Device.
- Attributes — where you add the
player_id/source_idattributes.