Get the area of the voice assistant to use in intent_script

I am trying to create an overloaded custom sentence that will automatically pass the area of the voice assistant activated if not specified. Is it possible to create a sentence of the form:

"Play CBC radio [[on|in] {media_player}]"

In this case, if the sentence “play cbc radio” is picked up by a voice assistant with a defined area, then the intent_script would be passed the area and the corresponding media_player would be used. If the sentence “play cbc radio in kitchen” is picked up, the kitchen media_player would be used.

For completeness, here are my 2 .yaml files:
custom_sentences:

language: "en"
intents:
  #- Play CBC radio [on {{ player }} ]
  PlayCBConPlayer:
    data:
      - sentences:
          - "Play CBC radio [on|in] {media_player}"

lists:
  media_player:
    values:
      - in: "kitchen"
        out: "media_player.kitchen"
      - in: "office"
        out: "media_player.office"
      - in: "basement"
        out: "media_player.basement_pool"
      - in: "pool"
        out: "media_player.basement_pool"

intent_script.yaml

PlayCBConPlayer:
  speech:
    text: "Playing CBC radio in {{ media_player }}."
  action:
    - service: script.squeezebox_play_cbc1
      data_template:
        player: "{{ media_player }}"

Yes trying to do this myself. Have it working well if I say the player name but without is a problem. I tried mirroring how the offical intents do it as shown here: https://github.com/home-assistant/intents/blob/a542bd34a21f70180a2c7a6a82071aa3f8e0e9f6/sentences/en/light_HassTurnOn.yaml

so I have:

intents:
  SetVolume:
    data:
      - sentences:
          - "(set|change|increase|decrease) <media_player> volume to {volume} [(percent|%)]"
          - "Turn <media_player> volume (up|down) to {volume} [(percent|%)]"
          - "((set|change|increase|decrease) the volume to {volume} [(percent|%)];[on ]<media_player>)"
          - "(Turn the volume (up|down) to {volume} [(percent|%)];[on ]<media_player>)"
      - sentences:
          - "(set|change|increase|decrease) [the] volume to {volume} [(percent|%)]"
          - "Turn [the] volume (up|down) to {volume} [(percent|%)]"
        slots:
          domain: "media_player"
        requires_context:
          area:
            slot: true

intent_script:
  SetVolume:
    action:
      service: "media_player.volume_set"
      data:
        entity_id: "{{ media_player }}"
        volume_level: "{{ volume / 100.0 }}"
    speech:
      text: "Volume set to {{ volume }} percent"

but I get this error

2024-02-03 22:14:39.695 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: 'media_player' is undefined when rendering '{{ media_player }}'
2024-02-03 22:14:39.699 ERROR (MainThread) [homeassistant.helpers.script.intent_script_setvolume] Intent Script SetVolume: Error executing script. Invalid data for call_service at pos 1: not a valid value for dictionary value @ data['entity_id']
2024-02-03 22:14:39.700 WARNING (MainThread) [homeassistant.helpers.intent] Received invalid slot info for SetVolume: not a valid value for dictionary value @ data['entity_id']

So perhaps the core doesn’t support the media_player domain yet?

Have you had any luck getting area populated for non media_players?

Trying to get the heating to fire in a specific room when I say that I’m cold.

I’m just getting a long alpha-numeric string read out as the area. This appears to be the area ID, but using area.name results in nothing in the speech text. Using area.attributes.name returns ‘An unexpected error occurred’.

Is there a way to get the area name?

intents:
  BoostRoomHeating:
    data:
      - sentences:
          - "I'm cold"
          - "It is cold [in here]"
          - "It's cold [in here]"
        requires_context:
          area:
            slot: true
BoostRoomHeating:
  speech:
    text: "Turned on heating in {{area}}"

FYI - figured it out. I had a mixture of alpha-numeric and plain strings in the areaIds.

Manually edited the core.area_registry to make id field more appropriate.

Then tweaked my intent & conversation files:

language: "en"
intents:
  BoostRoomHeating:
    data:
      - sentences:
        - "I'm cold"
        - "It is cold [<in_here>]"
        - "It's cold [<in_here>]"
        expansion_rules:
          in_here: "[ in] here"
        slots:
          domain: "climate"
        requires_context:
          area:
            slot: true
BoostRoomHeating:
  speech:
    text: "Turning on heating in {{ area }}"
  action:
    - service: input_boolean.turn_on
      target:
        entity_id: "input_boolean.boost_{{ area }}"

Not sure if that will help you guys

1 Like

Yes it does help actually. Still not 100% what I am after but now I have:

intents:
  PlayerPauseArea:
    data:
      - sentences:
          - "hold the music"
        requires_context:
          area:
            slot: true
intent_script:
  PlayerPauseArea:
    action:
      service: "media_player.media_pause"
      data:
        entity_id: "{{ expand(states.media_player) | selectattr('entity_id', 'in', area_entities(area)) | select('search', 'ma_') |map(attribute='entity_id') | join }}"
    speech:
      text: "Paused"

I love progress! Now to play with it some more so I can either call for a specific player or the area will be recognised but have it all in one intent. BTW the search is used to find the music assistant player as I have prefixed all their entity ids with ma_