Script variables and entities

Hello all,

Looking for some advice about the use of variables within scripts. I would like to set a variable to an entity ID. In this case a speaker.

I’ve read about the use of variables here and I can pass a variable from an automation into a script but I’d like to conditionally set an entity_id to a variable and use that to play on the required speaker.

I’ve looked through various examples but I’m sorry to say I can’t see something that fits. So:

Here is a field I am passing into the script. It contains the message:

announcement:
  selector:
    text: {}
  name: Announcement
  description: The announcement that should be played
  required: true

A variable I am trying to set with an IF statement:

alias: Set the speaker according to location
if:
  - condition: state
    entity_id: input_select.steve_location
    state: Downstairs
    alias: Steve location is downstairs
then:
  - variables:
      target_speaker: media_player.home_pod_mini_kitchen
    alias: Set the speaker variable to kitchen
else:
  - variables:
      target_speaker: media_player.google_home_speaker
    alias: Set the speaker location to the google speaker

The service call I am trying to use:

alias: Play the announcement on the selected speaker
service: chime_tts.say
data:
  final_delay: 0
  volume_level: "{{ states ('input_number.announcement_volume') }}"
  message: "{{ announcement }}"
  tts_platform: cloud
  chime_path: custom_chime_path_2
  cache: true
target:
  entity_id: "{{ target_speaker }}"

It errors out with this:

Have tried a few variants without success. Can I store and later use and entity_id in a variable or am I barking up the wrong tree?

Thanks for reading this.

Could the issue be that you’re setting the variable to the media player entity itself, and not its entity_id string value?

the issue is that a variable is valid only within the scope block where it was defined. and at the beginning of that scope block. so your target_speaker variable is defined within the “then” block and also within the “else” block and then gone.

could you post your entire automation for the second block (where you’re trying to define the variable). post that whole automation. it’ll be easier to show you how to do it that way.

1 Like

It depends on where the variable is created.

The variable target_speaker is defined exclusively within the scope of the if and else sections and is undefined outside of them. That’s likely why the following line is responsible for the error message. It exists outside the bounds of where the target_speaker variable is defined.

  entity_id: "{{ target_speaker }}"

Reference

Scope of variables


It’s not hard to fix but we would first have to see the complete scripts/automations because it’s unclear from the examples you posted (which appear to be fragments of one or more scripts/automations).

1 Like

taking a bit of a guess as to your automation, try something of this format.

trigger: []
condition: []
action:
  - variables:
      target_speaker: >
        {{ 'media_player.home_pod_mini_kitchen' 
        if (states('input_select.steve_location') == 'Downstairs') else
        'media_player.google_home_speaker' }}
  - service: script.whatever_your_script_name_is
    data:
      your_speaker_variable_name: "{{ target_speaker }}"

1 Like

Thanks, the blocks are the script. The idea is that it is called from an automation with a message sent to a field. The message is then played on speaker according to the value in the location input helper.

I vaguely remember a way to ‘export’ a variable, perhaps a response_variable so it available outside its own block. Is that right?

Perhaps it is better to use something like this instead:

target:
  entity_id: >
    {% if is_state('input_select.steve_location', 'Downstairs') %}
      media_player.home_pod_mini_kitchen
    {% else %}
      media_player.google_home_speaker
    {% endif %}

i undestand that the blocks are parts of the script. it’d be helpful to have the whole automation. if you don’t want to post that for some reason, then work from what i posted above.

wrt response_variable. no. that’s how you return a value from a script to the calling automation.

either take a look at my two posts… the first explains what is going wrong with what you had. the second is a total guess as to what you’re trying to do. but to move it from a guess to make it work… post your code and i or someone else can tell you specifically

yes, that approach will work if you only want to use it in one place. your origianl question was about how to make the variable work… which is then useful to use in multiple places. the code i provided will do that.

if you want to do this approach, a more concise method (but equivalent to what you have) is to do this:

target:
  entity_id: >
        {{ 'media_player.home_pod_mini_kitchen' if (states('input_select.steve_location') == 'Downstairs') else 'media_player.google_home_speaker' }}


either works. :slight_smile:
note, however, that if you’re using it to call a script, you’ll want to do data: not target:.

Here is a block within (a quite large automation) that calls the script. Presently there is an if statement here within the automation block that sets the speaker. I want to change it so the selection occurs within the script instead of the automation as I am calling the script from multiple automations. That way if I want to change the speakers I only have to do within the script.

alias: Select the speaker to send the announcement to
if:
  - condition: state
    entity_id: input_select.steve_location
    state: Downstairs
    alias: If Steve is downstairs play the announcement on the Kitchen speaker
then:
  - service: script.play_an_announcement
    metadata: {}
    data:
      announcement: Two hours to sunset
      target_speaker: media_player.home_pod_mini_kitchen
    alias: Play announcement down stairs
else:
  - alias: Play announcement on google speaker
    service: script.play_an_announcement
    metadata: {}
    data:
      announcement: Two hours to sunset
      target_speaker: media_player.google_home_speaker

ok. maybe i misunderstood then. in your original question you had asked about how to get the variable set first then use it later when you call the script.

sounds like now you want to move the whole logic into the script and out of the automation completely. if that’s the case and you’re willing to check input_select.steve_location inside the script then you should either do something like this if you only need to use it once:

target:
  entity_id: >
        {{ 'media_player.home_pod_mini_kitchen' 
        if (states('input_select.steve_location') == 'Downstairs') else 
        'media_player.google_home_speaker' }}

or this:

trigger: []
condition: []
action:
  - variables:
      target_speaker: >
        {{ 'media_player.home_pod_mini_kitchen' 
        if (states('input_select.steve_location') == 'Downstairs') else
        'media_player.google_home_speaker' }}
  - service: whatever.service_you_want_like_volume
    target:
      entity_id: "{{ target_speaker }}"
  - service: whatever.service_you_want_like_tts?
    target:
      entity_id: "{{ target_speaker }}"

if you need to refer to that target entity multiple times.

1 Like

Firstly, I apologise that my OP was unclear. Thanks very much for the information you’ve given. The example in your first code block looks right, I’ll give that a try. Thanks again for your help and patience, its very much appreciated.