Home Assistant

Voice satellite media duck

While an Assist satellite is listening, other media players in the room mute or drop in volume, then return to the level they had when the satellite goes idle.

Difficulty · IntermediateSetup · 20–40 minutesHA · current stable (Assist satellite)
Get the pack · from $19Have us set it up

A satellite that has to hear you over a television will miss the command, then answer into the same noise. This pack watches an assist_satellite entity. When it enters listening, every other selected media player mutes, or, if that player cannot mute, drops to a volume fraction you set. When the satellite has been idle for a few seconds, those players go back to the mute flag and volume they had before.

Entity ids are blueprint inputs (assist_satellite.room, media_player.room_speaker). Do not publish a device name from a live house.

Building the satellite itself is ESP32-S3 voice satellite. A plug that powers an amplifier when playback starts is speaker plug follows playback. A clock-based volume schedule is restart-proof volume ramp. This pack only borrows the volume for the length of a voice turn.

What problem it solves

You want the room quiet enough for the wake word and the command, and you want the music back at the same volume when the satellite is done, including on players that have no mute.

How it works

  1. Listening — the satellite state changes to listening. Before it changes anything, the blueprint writes a snapshot of each playing target into one input_text helper: which players it will mute, and the volume of each player it will turn down. The helper survives a Home Assistant restart. Automation variables do not.
  2. Leave the satellite alone — a player on the same device as the satellite is skipped. Muting that player mutes the reply. The skip list is a blueprint input. If the satellite has no media player, the list is empty.
  3. Mute or duck — players that support volume_mute are muted. Players that do not (some AirPlay and cast targets) get volume_set to the current level divided by the duck factor (pack default 3, so a player at 0.45 goes to 0.15). A player already paused is left paused. Ducking a paused player’s volume still matters if it resumes on its own.
  4. Idle hold — restore runs when the satellite has stayed idle for a few seconds (pack default 3). processing and responding are not idle. A one-second gap between listening and responding must not restore the television under the reply. A follow-up that returns to listening keeps the room quiet, because the satellite has not been idle long enough to restore.
  5. Restore — unmute only the players this run muted, and set volume only on the players this run ducked, using the snapshot from step 1. The snapshot is then cleared. A player the listener never touched stays as it is.
  6. Timeout — if the satellite never reaches a stable idle (a stuck listening state), a timeout (pack default 45 seconds) restores anyway so a failed pipeline does not leave the room muted.

A voice command that itself changes volume is easy to clobber. The restore writes the level saved at the start of listening. If the command was “set volume to 40%” on a player this pack ducked, the restore puts the old level back. Exclude that player, or send the volume command again after the satellite is idle.

Hardware notes

  • Satellite. Any assist_satellite entity. A Voice Preview Edition or the ESP32-S3 satellite pack both expose one. This page does not add a board. The build, the microphone, and the amplifier are the voice-satellite pack.
  • Players. One or more media_player entities in the same room. Select the entity that actually supports mute or volume. A duplicate player from a second integration (the same speaker via Music Assistant and via the speaker’s own integration) will be muted twice and can unmute itself in a loop. Pick one entity per speaker.
  • No extra hub. If the satellite and the players are already in Home Assistant, this is a blueprint and one text helper.

Snippet

The pack ships a blueprint. One player is shown. The pack loops the same steps for every selected player and skips the satellite’s own media player.

mode: single

triggers:
  - trigger: state
    entity_id: !input satellite
    to: listening

actions:
  - variables:
      snap: >-
        {# one entry per playing player: {'e': id, 'm': 1} to mute,
           or {'e': id, 'v': volume} to turn down #}
  - action: input_text.set_value
    target:
      entity_id: "{{ snap_e }}"
    data:
      value: "{{ snap | to_json }}"
  # mute or turn down each entry, then:
  - wait_for_trigger:
      - trigger: state
        entity_id: !input satellite
        to: idle
        for:
          seconds: "{{ hold | int }}"
    timeout:
      seconds: "{{ tmo | int }}"
  # restore exactly the entries in the snapshot, then clear it

Players that reject volume_mute take the duck path: the saved volume is divided by the duck factor on the way down and written back unchanged on the way up. A Home Assistant start also restores anything still in the snapshot.

Setup outline

  1. Confirm the satellite entity reaches listening and returns to idle in Developer Tools while you say the wake word.
  2. Add the pack’s package (one input_text helper, 255 characters, enough for about five players). It holds the snapshot between listening and restore.
  3. Import the blueprint. Select the satellite, the players, the skip list, the snapshot helper, the duck factor, the idle hold, and the timeout.
  4. Play audio on one player. Say the wake word. The player should go quiet before you finish the command, and come back a few seconds after the satellite is idle.
  5. Repeat with a player that has no mute. The volume should drop and then return to the same level, not to 100%.

Troubleshooting

  • The reply is quiet. The satellite’s own media player is in the target list. Add it to the skip list.
  • volume_mute is unsupported. That player uses the duck path. If volume_set is also unsupported, Home Assistant cannot change it. Leave it out of the targets. Pausing is a different action and will not resume a live broadcast where it left off, so this pack does not pause.
  • Volume returns, then drops, then returns. Two entities point at one speaker. Disable the extra entity or remove it from the targets.
  • Music stays quiet. The satellite never published idle for the hold time. Check the trace. The timeout should still restore. If the snapshot was empty, the player was not playing (or was unavailable) when listening started.
  • A volume command is undone. Expected if that player was ducked. The restore uses the level from the start of the turn. Exclude the player you want voice to control.
  • Unmute during the answer. The idle hold is 0, so processing was treated as done. Keep a few seconds of idle before restore.

Credits

Based on the community blueprint Voice PE — mute media players on listening, including the later volume-lower path for players that cannot mute. This write-up is an original overview of that mute-or-duck and restore, with the satellite’s own speaker skipped. It is not a paste of that blueprint.

Changelog

v1.0 · Oct 26, 2026: First publish.