Passing conditional variables from one script to another script

Hi all,

I have a script (let’s call it “child”) with a few optional variables. In that script I test if the optional variables are defined and if not so, then I use a default value that I also define within that script. The script is set up to deal with a specific entity and it is important that only entity is passed to it. So far so good and the script runs smoothly.

Now I also have a second script (let’s call it “parent”) that is there to enable the same procedure for multiple entities. So it accepts the same list of variables as “child”, however, potentially multiple entities, and then calls “child” for each entity separately. What I don’t know yet is how to test if a variable is defined within “parent” and if not, then simply not passing that variable at all to “child”, as the default value should obviously only be defined in one place and that is within “child”.

Minimal current setup looks like this (simplified!):

The automation:

alias: "Automation"
mode: single
trigger:
  ### whatever
action:
  - service: script.parentscript
    data:
      entity_id:
        - entity1
        - entity2

The “parent” script, which is the issue:

parentscript:
  alias: "parent"
  mode: queued
  fields: # only for illustration purposes here, strongly simplified
    entity_id # mandatory
    variable2 # optional
  sequence:
    - repeat:
        count: "{{ entity_id | length }}"
        sequence:
          - service: script.turn_on
            entity_id: script.childscript
            data_template:
              variables:
                name: "{{ entity_id[repeat.index - 1] }}"
                # and here is the issue, I would like to do something like (in natural language)
                # if variable2 is defined then pass
                #   variable2: "{{ variable2 }}"
                # else pass nothing

The “child” script that works

childscript:
  alias: "child"
  mode: parallel
  variables:
    default_variable2: 0.5
  fields: # only for illustration purposes here, strongly simplified
    name # mandatory
    variable2 # optional
  sequence:
    - service: xyz
      data_template:
        entity_id: "{{ name }}"
        var: "{{ variable2 if variable2 is defined else default_variable2 }}"

Would appreciate if anybody could help out here. Thank you!

I’m just going to start by saying that the situation you’re presenting sounds like you’re making things particularly complicated for no reason, as whatever calls parent could just as easily call child directly.

But I’m not going to get into it any deeper because the “let’s call it this” and “let’s call it that” style of questions here often leads to someone spending hours trying to fix the problem you asked in post one, only for you to provide the ‘real’ code in post thirty-five and the solution no longer being suitable and someone having to spend even longer trying to fix it.

So, my suggestion is:

A - try and simplify your process
B - show us the REAL code and define a REAL example of usage

I know you probably don’t intend to waste anyone’s time, but threads that start like this one invariably do accidentally :slightly_smiling_face:

1 Like

Hi Marc,

indeed wanted to simplify things. The “child” script calls a specific google home device, saves the volume there, adjusts the volume, then broadcasts a message and then turns the volume back. The parent script is there to a play a specific message on multiple google home devices at the same time. Therefore the child script runs in parallel for multiple devices and the parent script runs in a queued mode to not have conflicts with multiple messages.

The full scripts (with additional complexity) - parent:

cast_msg_ghome:
  alias: 'Broadcast a message on one or more devices'
  description: 'Broadcasts a message on set of Google Home devices at a given volume, then restores the original volume of each device'
  mode: queued
  fields:
    entity_id:
      description: 'Entity ID of the device the message should be broadcasted to'
      example: 'media_player.xyz'
    msg:
      description: 'Message to be broadcasted'
      example: 'This is a message'
    lang:
      description: 'Language the message is in'
      example: 'de'
    vol:
      description: 'Target volume for broadcasted message'
      example: 0.5
  sequence:
    - repeat:
        count: "{{ entity_id | length }}"
        sequence:
          - service: script.turn_on
            entity_id: script.cast_msg_single_ghome
            data_template:
              variables:
                device_name: "{{ entity_id[repeat.index - 1] }}"
                msg: "{{ msg }}"
                ### this is where the optional variables would need to be put

And the “child” script:

cast_msg_single_ghome:
  alias: 'Broadcast a message on a single device'
  description: 'Broadcasts a message on a specific Google Home device at a given volume, then restores the original volume'
  mode: parallel
  variables:
    timeout_value: 30
    curr_vol:
      name: 'Current volume'
      min: 0
      max: 1
    default_lang: 'de'
    default_vol: 0.7
  fields:
    device_name:
      description: 'Entity ID of the device the message should be broadcasted to'
      example: 'media_player.xyz'
    msg:
      description: 'Message to be broadcasted'
      example: 'This is a message'
    lang:
      description: 'Language the message is in'
      example: 'de'
    vol:
      description: 'Target volume for broadcasted message'
      example: 0.5
  sequence:
    - service: media_player.play_media
      data_template:
        entity_id: "{{ device_name }}"
        media_content_type: music
        # media_content_id: "{{ states('input_text.base_url') + '/local/audio/250-milliseconds-of-silence.mp3' }}"
        media_content_id: https://github.com/anars/blank-audio/raw/master/250-milliseconds-of-silence.mp3
    - delay:
        milliseconds: 250
    - variables:
        curr_vol: "{{ state_attr( device_name ,'volume_level') | float }}"
    - service: media_player.volume_set
      data_template:
        entity_id: "{{ device_name }}"
        volume_level: "{{ vol if vol is defined else default_vol }}"
    - service: tts.google_say
      data_template:
        entity_id: "{{ device_name }}"
        message: "{{ msg }}"
        language: "{{ lang if lang is defined else default_lang }}"
    - delay:
        seconds: 2
    - wait_template: "{{ not(is_state( device_name , 'playing')) }}"
      timeout:
        seconds: "{{ timeout_value }}"
    - service: media_player.volume_set
      data_template:
        entity_id: "{{ device_name }}"
        volume_level: "{{ curr_vol | float }}"

Not sure though if this really simplifies the problem :wink: Also, I don’t think I can combine the 2 scripts as long as I want the messages to be broadcasted in parallel on the given devices and the devices having different volume levels set to start with.

Okay, I did find a solution that works, even if not very elegant. If someone has a nicer solution, of course would be happy to learn how to not pass the respective variables depending on a test if it is defined at all or not. My solution:

I am passing the volume as follows in the “parent” script:

  sequence:
    - repeat:
        count: "{{ entity_id | length }}"
        sequence:
          - service: script.turn_on
            entity_id: script.cast_msg_single_ghome
            data_template:
              variables:
                device_name: "{{ entity_id[repeat.index - 1] }}"
                msg: "{{ msg }}"
                vol: "{{ vol if vol is defined else 0 }}"

and then I am simply testing for it in the “child” script:

    - service: media_player.volume_set
      data_template:
        entity_id: "{{ device_name }}"
        volume_level: "{{ vol if vol is defined and vol>0 else default_vol }}"

Just got back to this thread so haven’t read the big post in the middle properly, but is there any reason to not put the sequence of the child script in the parent script? Isn’t it more likely that your ‘group’ messages would want to be sent to a group of devices at the same time rather than send the same message to multiple devices one after the other?

But yeah, having a ‘default’ if nothing is passed to a script is the way to do it.

Thanks for coming back! Yep, ideally they are sent at the same time, however, I have the complication that I am saving the original volume in the single_script, then change it, and then restore it. Since the original volume is specific for each device, I need to save it separately and that’s why I have a separate script for it. if there is a simpler approach, I am all for it :smile:

I haven’t tried it but I believe the scene.create service is used to save the current state/attributes of devices, so your script would be

  • create scene to save what the current state/attributes of the media players are
  • send the message to the desired group
  • apply the scene to resume the media players to what they were doing before