TapHome

Denon HEOS

Packet Parser → TCP
Submitted by
Last updated: 04. 2026
Denon HEOS

Denon HEOS is a wireless multi-room audio platform built around the HEOS Command Line Interface (CLI) — a text-based protocol that exposes every speaker, soundbar, amplifier and HEOS-enabled component on the local network over TCP port 1255. TapHome uses this protocol to control playback, volume, mute and play mode on HEOS speakers without any cloud dependency.

The template covers the full HEOS wireless lineup (HEOS 1, 3, 5, 7), the HEOS Bar and HomeCinema soundbars, the HEOS Amp / Link / Drive components, the HEOS Sub, and the newer Denon Home 150 / 250 / 350 speakers and Sound Bar 550. One HEOS device on the LAN is enough — the CLI exposes every other HEOS player in the network through its player/get_players endpoint.

This template is for HEOS speakers, soundbars and HEOS-enabled amplifiers only. Denon and Marantz AVR receivers (AVR-X series, SR series, etc.) use a separate Denon/Marantz Telnet control protocol on port 23 and are not compatible with this template, even on models that also feature HEOS Built-in.

Network connection

HEOS communicates over TCP on port 1255 using plain-text ASCII commands terminated with \r\n and returns JSON responses. No authentication is required — any device on the same LAN can connect to the CLI port.

Before TapHome can control the device, the HEOS speaker must be set up with the HEOS mobile app:

  1. Install the HEOS App (Android / iOS) on a phone or tablet on the same Wi-Fi network.
  2. Connect the HEOS device to Wi-Fi or Ethernet through the app’s initial setup wizard.
  3. Make sure firmware is up to date (the template is built against HEOS CLI v1.17, corresponding to firmware 2.41.140 or newer).
  4. Note the speaker’s IP address — found in the HEOS app under Settings → My Devices → About, or in the router’s DHCP client list.

Use a static IP or a DHCP reservation for the HEOS device that TapHome connects to. The speaker acts as a gateway to every other HEOS player, so a stable address keeps the whole ecosystem reachable.

HEOS CLI has no authentication. Keep the speaker on a trusted LAN segment — any device with network access to port 1255 can control playback.

Configuration

TapHome connection details

During template import in the TapHome app, enter the HEOS speaker’s IP address for the IP Address parameter. The TCP port 1255 and protocol framing are already set in the template. TapHome will open a single persistent TCP connection and pipeline HEOS CLI commands over it.

PlayerId initialization

Every heos://player/* command requires a player id (pid) — a large signed integer that HEOS assigns to each speaker on the network. The template stores this as the PlayerId custom variable. Because HEOS generates pids dynamically per network, the template ships with a placeholder value (-1857880384) that must be replaced on first setup.

The module exposes two service actions to discover and assign the pid. Run them once after importing the template:

  1. Get Players — sends heos://player/get_players and caches the JSON payload into the PlayersResponse module variable. The Players service attribute on the module then displays the list of HEOS players visible on the network, including their name, pid, model and IP address.
  2. Set Player Id — takes an Index parameter (0-based position in the Players array) and writes the matching pid into the PlayerId custom variable. Pick the index of the speaker you want TapHome to control — the same TapHome module is bound to one HEOS player at a time.

After these two steps, all child devices (Volume, Mute, Play, Pause, etc.) work against the selected speaker. To control a second HEOS player, import a second instance of the template against the same (or another) HEOS IP and repeat the Set Player Id step with a different index.

If the Players attribute is empty on the first run, the HEOS CLI module may be in dormant mode. Run Get Players a second time after a few seconds — HEOS spawns the CLI core on first connection and may take a moment to enumerate all players.

Device variables

Two child devices have per-device custom variables configurable after template import:

DeviceVariableDefaultNotes
Play URLURLPixabay doorbell MP3Any direct HTTP(S) URL to an audio stream or file
Volume Up / Volume DownStep5Volume change per press; HEOS spec limits the range to 1–10

Open each device’s detail in the TapHome app and set these variables to the values you need. URL-encoded special characters in the stream URL (&, =, %) are handled by the template script.

Device capabilities

The template exposes 12 child devices covering playback, volume, mute and URL streaming for a single HEOS player.

Volume control

The Volume device is a dimmer that reads heos://player/get_volume (level 0–100) and scales it to the 0.0–1.0 dimmer range (Le := level / 100). Writes send heos://player/set_volume with ROUND(Le * 100). Volume is polled every 2.5 seconds so external volume changes from the HEOS app or another controller are reflected in TapHome on the next cycle.

Volume Up and Volume Down are push-button devices that send heos://player/volume_up and heos://player/volume_down with the configurable Step size. Useful for binding to physical wall switches or smart rules.

Mute

Mute is a switch that reads heos://player/get_mute and writes heos://player/set_mute with state=on|off. When muted, the speaker is silenced without changing the underlying volume level.

Transport

Four push-button devices cover basic transport:

  • Play — writes heos://player/set_play_state?state=play
  • Pause — writes heos://player/set_play_state?state=pause
  • Stop — writes heos://player/set_play_state?state=stop
  • Next Track — writes heos://player/play_next
  • Previous Track — writes heos://player/play_previous

These are write-only buttons — the template does not poll the current play state back, so transport buttons do not reflect whether the speaker is actively playing.

Play mode

Play Mode is a multi-value switch that combines the HEOS repeat and shuffle flags into a single 6-state enum read and written via heos://player/get_play_mode and heos://player/set_play_mode:

ValueMode
0No repeat, no shuffle
1Repeat all
2Repeat one
3Shuffle, no repeat
4Shuffle, repeat all
5Shuffle, repeat one

The XML template reserves slots 6–9 in the multi-value configuration but they are unused — values 0–5 are the only reachable states.

Quick Select presets

Quick Select is a write-only multi-value switch (1–9) that triggers a HEOS QuickSelect preset via heos://player/play_quickselect?id={1-9}. Quick selects are saved on the player itself (typically through a paired Denon AVR or HEOS Bar) and can store a pre-configured input, source or station.

Quick Select is defined in HEOS spec §4.2.24 as an AVR-only command. It works on HEOS Amp, HEOS Link, HEOS Bar and HEOS-enabled AVR/receiver products, but will return an error on stand-alone wireless HEOS speakers such as HEOS 1, 3, 5 and 7.

Play URL (custom stream)

Play URL is a push-button that streams an arbitrary HTTP(S) audio URL to the selected HEOS player via heos://browse/play_stream?pid={PlayerId}&url={URL}. The URL device variable holds the stream target — ships with a Pixabay doorbell MP3 as a sample and is typically overridden with an internet radio stream, notification sound or any direct audio URL.

Good uses: doorbell notifications, voice announcements from a local HTTP server, playing a fixed internet radio URL without HEOS Favorites.

Additional capabilities

The HEOS CLI protocol exposes many features beyond what the template currently implements. These can be added in a future template update:

  • Now Playing metadata (player/get_now_playing_media) — current track title, artist, album and artwork URL as string attributes.
  • Play state feedback (player/get_play_state) — read-back of play / pause / stop so transport buttons reflect the actual state.
  • Toggle Mute (player/toggle_mute) — single-command mute toggle without reading state first.
  • Queue management (player/get_queue, play_queue, clear_queue) — browse and manipulate the current play queue.
  • Favorites and presets (browse/play_preset) — trigger saved HEOS Favorites by preset number, simpler than a raw Play URL for saved stations.
  • Physical input selection (browse/play_input) — switch to AUX / Line-In on HEOS Amp, Link and AVR models.
  • Multi-room grouping (group/*) — create, destroy and volume-control HEOS groups for synchronized whole-home playback.
  • Firmware maintenance (system/check_update, system/reboot) — trigger firmware update checks and remote reboots.
  • Change events (system/register_for_change_events) — opt-in push notifications for volume, state and now-playing changes instead of polling.
  • HEOS account sign-in (system/sign_in) — required for accessing paid streaming services (Tidal, Amazon Music, Deezer, TuneIn custom stations) from TapHome.

Troubleshooting

Players attribute is empty after Get Players

HEOS runs its CLI module in dormant mode and spawns the core on first socket connection, which can take a few seconds. Wait 5–10 seconds and run Get Players again. If still empty, verify that:

  1. TapHome CCU can reach the speaker’s IP on TCP port 1255 (same LAN / subnet, no firewall between them).
  2. The HEOS device is fully online in the HEOS mobile app — CLI is unavailable until initial Wi-Fi setup is complete.
  3. The IP address in the module still matches the speaker — DHCP renewals can change it. Use a DHCP reservation or a static IP.
All device commands return “ID Not Valid”

The PlayerId custom variable either still holds the template default (-1857880384) or points to a pid that no longer exists (e.g., the speaker was factory-reset). Re-run Get Players followed by Set Player Id with the correct index.

Play URL action does nothing or returns an error

The Play URL script in the current template has a known quirk: it references playerId (lowercase) instead of the PlayerId custom variable. If the action has no effect, open the Play URL device script in the TapHome app and correct the variable name to match PlayerId. After this fix, the action sends heos://browse/play_stream correctly. Also make sure the stream URL is reachable from the HEOS speaker and uses a supported audio format (MP3, AAC, WAV — HLS streams are not reliably accepted).

Quick Select returns an error

Quick Select only works on HEOS-enabled AVR, amplifier and soundbar products. On wireless HEOS speakers (HEOS 1, 3, 5, 7 and Denon Home speakers without soundbar features), use Play URL or favorite streams instead.

Changes made in the HEOS app are not visible in TapHome

The template polls state every 2.5 seconds for Volume, Mute and Play Mode. Transport state (Play / Pause / Stop) is not polled — those are push-buttons only. If an external controller changed the play mode or paired a new streaming account, disconnecting and reconnecting the TapHome module to the speaker forces a fresh CLI session.

Multiple HEOS players — how to control more than one

One TapHome module controls exactly one HEOS player (one pid). To control a second speaker, import a second instance of the Denon HEOS template. The IP address can point to the same HEOS device — the CLI on one speaker can reach every other HEOS player on the network — and the Set Player Id action with a different index binds the second module to a different speaker.

Available devices

Denon HEOS Speaker Module
Service Attributes
PlayersJSON array of HEOS players reachable on the network (name, pid, model, IP, version). Populated by the Get Players action; used to pick the Index for Set Player Id.
Service Actions
Get PlayersDiscovers all HEOS players on the network by sending heos://player/get_players. The response is cached into the Players attribute and must be run before Set Player Id.
Set Player IdBinds this TapHome module to one HEOS player. Takes the 0-based Index from the Players list and writes the matching pid into the PlayerId custom variable. Required after Get Players before any child device works.
Custom Variables

Denon HEOS speaker

Write (module)
# 1. Run Get Players action
					# 2. Save and go back
					# 3. Review the Players attribute in the top of page
					# 4. Run Set Player Id with index of your choice
Listener
VAR response := TOSTRING(RECEIVEDBYTES);
					VAR command := PARSEJSON(response, "heos.command", 1);
					VAR result := PARSEJSON(response, "heos.result", 1);
					VAR message := PARSEJSON(response, "heos.message", 1);

					IF (result = "fail" AND INDEXOF(message, "ID Not Valid") >= 0)
					ADDERROR("PlayerId is not set properly.");
					END

					IF (command = "player/get_players")
					IF (result = "fail")
					ADDERROR("Error: " + message);
					ELSE
					PlayersResponse := response;
					END
					END
Service Attributes
Players
PARSEJSON(PlayersResponse, "payload");
Service Actions
Get Players
SENDDATA("heos://player/get_players");
Set Player Id
Parameters: Index (0–20 Index)
PlayerId := PARSEJSON(PlayersResponse,"payload[" + Index + "].pid");
Mute Speaker Switch

Mutes or unmutes audio output on the selected HEOS player without changing the underlying volume level.

boolean switch
Values / States: Muted · Unmuted

Mute Speaker

Read switch state
SENDDATA("heos://player/get_mute?pid=" + PlayerId);
Write switch state
VAR mute := SWITCH(St, 0, "off", 1, "on", "off");
							SENDDATA("heos://player/set_mute?pid=" + PlayerId + "&state=" + mute);
Listener
VAR responseJson := TOSTRING(RECEIVEDBYTES);

							IF(PARSEJSON(responseJson, "heos.command", 1) = "player/get_mute")
							VAR mute := PARSETEXT(responseJson, "state=");
							St := SWITCH(mute, "off", 0, "on", 1, 0);
							END
Next Track Push Button
button push

Next Track

Write button state
SENDDATA("heos://player/play_next?pid=" + PlayerId);
Pause Push Button
button push

Pause

Write button state
SENDDATA("heos://player/set_play_state?pid=" + PlayerId + "&state=pause")
Play Push Button
button push

Play

Write button state
SENDDATA("heos://player/set_play_state?pid=" + PlayerId + "&state=play");
Play Mode Multi-value Switch

Combined repeat and shuffle state as a 6-value enum — 0 no repeat, 1 repeat all, 2 repeat one, 3 shuffle, 4 shuffle + repeat all, 5 shuffle + repeat one.

enum multi-value
Values / States: No repeat · Repeat all · Repeat 1 · Shuffle, no repeat · Shuffle, repeat all · Shuffle, repeat one

Play Mode

Read switch state
SENDDATA("heos://player/get_play_mode?pid=" + PlayerId);
Write switch state
VAR repeat := SWITCH( IF(Mu > 2, Mu - 3, Mu), 0, "off", 1, "on_all", 2, "on_one", "off");
							VAR shuffle := IF(Mu > 2, "on", "off");
							SENDDATA("heos://player/set_play_mode?pid=" + PlayerId + "&repeat=" + repeat + "&shuffle=" + shuffle);
Listener
VAR responseJson := TOSTRING(RECEIVEDBYTES);
							VAR command := PARSEJSON(responseJson, "heos.command", 1);
							VAR result := PARSEJSON(responseJson, "heos.result", 1);

							IF (command = "player/get_play_mode")
							IF (result = "fail")
							VAR errorMessage := PARSEJSON(responseJson, "heos.message", 1);
							ADDERROR("Error: " + errorMessage);
							ELSE
							VAR repeat := PARSETEXT(responseJson, "repeat=", "&");
							VAR shuffle := PARSETEXT(responseJson, "shuffle=");
							Mu := SWITCH(repeat, "off", 0, "on_all", 1, "on_one", 2, 0) + SWITCH(shuffle, "off", 0, "on", 3, 0);
							END
							END
Play URL Push Button

Streams an arbitrary HTTP(S) audio URL to the HEOS player (doorbell sounds, internet radio, voice announcements). The URL is configured per device through the URL custom variable.

button push
Variable: URL

Play URL

Write button state
SENDDATA("heos://browse/play_stream?pid=" + playerId + "&url=" + URL);
Listener
VAR response := TOSTRING(RECEIVEDBYTES);
							VAR command := PARSEJSON(response, "heos.command", 1);
							VAR result := PARSEJSON(response, "heos.result", 1);
							VAR message := PARSEJSON(response, "heos.message", 1);

							IF (command = "browse/play_stream")
							IF (result = "fail")
							ADDERROR("Error: " + message);
							ELSE
							VAR success := response;
							END
							END
Previous Track Push Button
button push

Previous Track

Write button state
SENDDATA("heos://player/play_previous?pid=" + PlayerId);
Quick Select Multi-value Switch

Triggers one of the HEOS QuickSelect presets 1–9 stored on the player. AVR / HEOS Bar / HEOS Amp only — not supported on plain HEOS wireless speakers.

enum multi-value

Quick Select

Write switch state
IF(Mu != 0)
							SENDDATA("heos://player/play_quickselect?pid=" + PlayerId + "&id=" + Mu);
							END

							# To make this work like a switch, create a following script.
							#
							# IF(Mu != 0)
							#   SLEEP(100);
							#   Mu := 0;
							# END
Stop Push Button
button push

Stop

Write button state
SENDDATA("heos://player/set_play_state?pid=" + PlayerId + "&state=stop")
Volume Dimmer

Dimmer control of the HEOS player volume. HEOS level 0–100 is mapped to the 0.0–1.0 dimmer range and polled every 2.5 seconds.

numeric Unit: % dimmer

Volume

Read level
SENDDATA("heos://player/get_volume?pid=" + PlayerId)
Write level
SENDDATA("heos://player/set_volume?pid=" + PlayerId + "&level=" + ROUND(Le*100))
Listener
VAR responseJson := TOSTRING(RECEIVEDBYTES);
							VAR command := PARSEJSON(responseJson, "heos.command", 1);
							VAR result := PARSEJSON(responseJson, "heos.result", 1);

							IF (command = "player/get_volume")
							IF (result = "fail")
							VAR errorMessage := PARSEJSON(responseJson, "heos.message", 1);
							ADDERROR("Error: " + errorMessage);
							ELSE
							Le := PARSETEXT(responseJson, "level=") / 100.0;
							END
							END
Volume Down Push Button

Decreases volume by the configured Step (default 5, HEOS allows 1–10) through the heos://player/volume_down command.

button push
Variable: Step

Volume Down

Write button state
SENDDATA("heos://player/volume_down?pid=" + PlayerId + "&step=" + Step);
Volume Up Push Button

Increases volume by the configured Step (default 5, HEOS allows 1–10) through the heos://player/volume_up command.

button push
Variable: Step

Volume Up

Write button state
SENDDATA("heos://player/volume_up?pid=" + PlayerId + "&step=" + Step);
Connection: Packet Parser → TCP
Possible improvements (14)
  • Now Playing Metadata — Current track artist, album, title, artwork URL, media_id — would require string attributes and a listener to cache the response
  • Play State (read) — Reads play|pause|stop back from the player. Template only writes play state (Play/Pause/Stop buttons) without feedback
  • Toggle Mute — Single-command mute toggle without reading current state; could be a second push-button
  • Check Firmware Update — Trigger firmware update check — useful as maintenance action
  • Heart Beat / Connection Health — Periodic heart_beat command for connection liveness; could map to a module-level online/offline sensor
  • Reboot Speaker — Remote reboot of the HEOS device — natural service action
  • Play Queue — Full queue management (get, play item, remove, save as playlist, clear, move). Template has no queue exposure
  • Music Sources / Browse — Browse and search streaming services (TuneIn, local library, favorites, playlists). Not exposed in template
  • Favorites / Preset Stations — Play a favorite station by preset number 1–N; simpler than Play URL for saved stations
  • Input Source (AUX / Line-In) — Switch to a physical input (inputs/aux_in_1, inputs/line_in_1, etc.) — only applicable to AVR/Amp/Link models
  • Group / Multi-Room Control — Create/destroy groups, group volume, group mute — enables multi-room synchronized playback across HEOS speakers. Not exposed in template
  • Player Info (name, model, version, IP) — Static metadata about the player; useful for diagnostics
  • Change Events (unsolicited push) — Register for change events via system/register_for_change_events and receive push updates (volume, state, now playing, queue). Template relies on polling only
  • HEOS Account Sign In / Out — Required for access to paid streaming services and cloud favorites; no hooks in template

Sources