Sending variable ONLY IF it is defined (optional variables)

Cannot wrap my head around what I need to do here. Trying to wrap a python service call that isn’t designed to handle multiple entity ids, into a script. But I cannot figure out how to send a variable if and ONLY if it’s defined.

The code: (the count and entity_id templates are working and can be ignored, all they do is create a dict full of every entity id that follows the filter.)

repeat:
  count: >-
    {{ ( states.switch | map(attribute='entity_id') | select(">",
    "switch.adaptive_lighting_al_") | select("<",
    "switch.adaptive_lighting_al_z") | join( "," ) ).split( "," ) | length }}
  sequence:
    - service: adaptive_lighting.change_sunlight_settings
      data:
        entity_id: |-
          {{ (states.switch
              | map(attribute="entity_id")
              | select(">", "switch.adaptive_lighting_al_")
              | select("<", "switch.adaptive_lighting_al_z")
              | join(",")).split(",")[repeat.index-1]
          }}
        use_config_defaults: '{{ use_config_defaults | default("off") }}'
        use_actual_sunrise_time: '{{ using_real_sunrise_time }}'
        use_actual_sunset_time: '{{ using_real_sunset_time }}'
        max_brightness: '{{ max_brightness | default }}'
        max_color_temp: '{{ max_color_temp | default }}'
        min_brightness: '{{ min_brightness | default }}'
        min_color_temp: '{{ min_color_temp | default }}'
        sleep_brightness: '{{ sleep_brightness | default }}'
        sleep_color_temp: '{{ sleep_color_temp | default }}'
        sunrise_offset: '{{ sunrise_offset | default }}'
        sunrise_time: '{{ sunrise_time | default }}'
        sunset_offset: '{{ sunset_offset | default }}'
        sunset_time: '{{ sunset_time | default }}'
        transition: '{{ transition | default }}'

The error I’m getting is usually something like ‘max_brightness expected int got None’ since it’s the first variable that is optional.
I’ve tried filtering with default(None), default(unknown), even tried sending an int out of range default(-1) to see if i could bypass it somehow. No dice. Also tried declaring different variables in the ‘variables’ section of the script and sending those. Didn’t work either.
I realize this is probably out of the scope of what I should be doing with Home Assistant but:

  1. I really don’t want to rewrite the python function
  2. I do not want to have every single service call written out for every possible amount of variables sent to the script.

Please help.

To reiterate, apparently the way Home Assistant service calls work is if a variable inside of data is specifically written, it will attempt to parse that variable, even if it’s (None, unknown, or not EVEN defined?)

bump. Anyone have any idea how I can get this done?

Can you not just say something like

{{ max_brightness | default('0') }}

??

But I need it to be null (or none or whatever) so the python integration uses its stored value, otherwise it’s setting the max brightness as 0 or whatever value every time if it’s not specifically defined in the parent service call.

Create a variable for the entity_id and set the defaults to the entity’s current value.

repeat:
  count: >-
    {{ ( states.switch | map(attribute='entity_id') | select(">",
    "switch.adaptive_lighting_al_") | select("<",
    "switch.adaptive_lighting_al_z") | join( "," ) ).split( "," ) | length }}
  sequence:
    - variables:
        entity_id: >
          {{ (states.switch
              | map(attribute="entity_id")
              | select(">", "switch.adaptive_lighting_al_")
              | select("<", "switch.adaptive_lighting_al_z")
              | join(",")).split(",")[repeat.index-1] }} 

    - service: adaptive_lighting.change_sunlight_settings
      data:
        entity_id: '{{ entity_id }}'
        use_config_defaults: '{{ use_config_defaults | default("off") }}'
        use_actual_sunrise_time: '{{ using_real_sunrise_time | default(state_attr(entity_id,"use_actual_sunrise_time") }}'
        use_actual_sunset_time: '{{ using_real_sunrise_time | default(state_attr(entity_id,"use_actual_sunset_time") }}'
        etc...

There is no entity id that contains these values, they’re solely stored in an unreachable spot inside of adaptive lighting. What I need is to send null or none or unknown or whatever this syntax calls null so adaptive_lighting.change_sunlight_settings will use its values upon receiving None.

Have you tried setting the default to a blank string?

min_color_temp: "{{ min_color_temp | default('') }}"

Arrgh I was really hoping that one would work.

error: expected int for dictionary value @ data[‘min_color_temp’]. Got None

it’s like home assistant is completely overriding any detection of null and forcing its syntax before it gets anywhere near the service call. I get that this is more noob friendly approach but it’s seriously limiting this script’s potential.

It seems as though if a variable like ‘min_color_temp’ is defined anywhere in the service call, even if the value is None or Null or “” it’ll expect a valid value within the range.

so my question is: WTH is it sending when a variable like ‘min_color_temp’ is completely OMITTED from the service call? I’m still able to check against None/null in the python integration if that value is omitted so why can’t I just send that null value inside the script?

It is the adaptive_lighting.change_sunlight_settings service call that is expecting an integer value. Home Assistant doesn’t care what data you pass to the service. If you are defining the variable in this service call then it needs to be an integer. The service handles what to do if it’s not defined.

You can use a choose structure to define and choose service calls depending on the variables being used, but you have a lot of variables there that would be really messy.

I guess you could try build a dynamic dict of parameters/values as a variable and pass that to the service data. I think that would work? I’ve never tried it.

Is there really no way to explicitly undefine a variable if it evaluates to none?
How exactly would I build a dynamic dict of parameters?
It sounds like you’re saying I’d have to have a separate choose option for each amount of dynamic arguments passed to the script, which means I’d have 14 different choose options all with repetitive code. Is that really the only way to accomplish this?

No I’m saying that way would suck. I have a better idea and I think it will work.

In your original post are those all the possible values that can be sent to adaptive_lighting.change_sunlight_settings?

Can post a copy of the full script?

Certainly.

alias: Adaptive Lighting - Change sunlight settings
sequence:
  - repeat:
      count: >-
        {{ ( states.switch | map(attribute='entity_id') | select(">",
        "switch.adaptive_lighting_al_") | select("<",
        "switch.adaptive_lighting_al_z") | join( "," ) ).split( "," ) | length
        }}
      sequence:
        - service: adaptive_lighting.change_sunlight_settings
          data:
            entity_id: |-
              {{ (states.switch
                  | map(attribute="entity_id")
                  | select(">", "switch.adaptive_lighting_al_")
                  | select("<", "switch.adaptive_lighting_al_z")
                  | join(",")).split(",")[repeat.index-1]
              }}
            use_config_defaults: '{{ use_config_defaults | default("off") }}'
            use_actual_sunrise_time: '{{ using_real_sunrise_time }}'
            use_actual_sunset_time: '{{ using_real_sunset_time }}'
            max_brightness: '{{ max_brightness | default("") }}'
            max_color_temp: '{{ max_color_temp | default(-1) }}'
            min_brightness: '{{ min_brightness | default(-1) }}'
            min_color_temp: '{{ min_color_temp | default("") }}'
            sleep_brightness: '{{ sleep_brightness | default(-1) }}'
            sleep_color_temp: '{{ sleep_color_temp | default(-1) }}'
            sunrise_offset: '{{ sunrise_offset | default(-1) }}'
            sunrise_time: '{{ sunrise_time | default(-1) }}'
            sunset_offset: '{{ sunset_offset | default(-1) }}'
            sunset_time: '{{ sunset_time | default(-1) }}'
            transition: '{{ transition | default(-1) }}'
variables:
  using_real_sunrise_time: '{{ "off" if sunrise_time is defined else "on" }}'
  using_real_sunset_time: '{{ "off" if sunset_time is defined else "on" }}'
mode: single

Give this a whirl and let me know what happens.

Adaptive Lighting Change Sunlight Settings
adaptive_lighting_change_sunlight_settings:
  alias: 'Adaptive Lighting - Change Sunlight Settings'
  fields:
    use_config_defaults:
      description: ''
    max_brightness:
      description: ''
    max_color_temp:
      description: ''
    min_brightness:
      description: ''
    min_color_temp:
      description: ''
    sleep_brightness:
      description: ''
    sleep_color_temp:
      description: ''
    sunrise_offset:
      description: ''
    sunrise_time:
      description: ''
    sunset_offset:
      description: ''
    sunset_time:
      description: ''
    transition:
      description: ''
  variables:
    use_config_defaults: "{{ use_config_defaults|default('off') }}"
    use_actual_sunrise_time: "{{ 'off' if sunrise_time == empty else 'on' }}"
    use_actual_sunset_time: "{{ 'off' if sunset_time  == empty else 'on' }}"
    max_brightness: "{{ max_brightness|default('') }}"
    max_color_temp: "{{ max_color_temp|default('') }}"
    min_brightness: "{{ min_brightness|default('') }}"
    min_color_temp: "{{ min_color_temp|default('') }}"
    sleep_brightness: "{{ sleep_brightness|default('') }}"
    sleep_color_temp: "{{ sleep_color_temp|default('') }}"
    sunrise_offset: "{{ sunrise_offset|default('') }}"
    sunrise_time: "{{ sunrise_time|default('') }}"
    sunset_offset: "{{ sunset_offset|default('') }}"
    sunset_time: "{{ sunset_time|default('') }}"
    transition: "{{ transition|default('') }}"
    options: >
      {% set option_dict = namespace(value='') %}
      {% set options = ['use_config_defaults','use_actual_sunrise_time','use_actual_sunset_time',
          'max_brightness','max_color_temp','min_brightness','min_color_temp','sleep_brightness',
          'sleep_color_temp','sunrise_offset','sunrise_time','sunset_offset','sunset_time','transition'] %}
      {% set values = [use_config_defaults,use_actual_sunrise_time,use_actual_sunset_time,
          max_brightness,max_color_temp,min_brightness,min_color_temp,sleep_brightness,
          sleep_color_temp,sunrise_offset,sunrise_time,sunset_offset,sunset_time,transition] %}
      {% for item in options %}
        {% if values[loop.index0] != '' %}
          {% set option_dict.value = option_dict.value
              ~ '"' ~ item ~ '":"'
              ~ values[loop.index0] ~ '"' ~ ',' %}
        {% endif %}
      {% endfor %}
      {{ '{' ~ option_dict.value[:-1] ~ '}' }}
  sequence:
    # you can delete this when done debuggin
    - service: system_log.write
      data:
        message: '{{ options }}'

    - service: adaptive_lighting.change_sunlight_settings
      data: '{{ options }}'

@th3w1zard1 I made a small edit. ‘is defined’ should be changed to == empty for the sunrise/sunset variables. I made the change on this post. Just wanted to make sure you saw the edit.

I’m honestly sorry I went AWOL on this thread. I don’t know why I never tried this, I guess I gave up on the idea. I ended up doing this the long way and just reducing the variables to the ones I needed.

Fast forward to today, and, well I just rewrote the change_sunlight_settings() call to use another function and once again I was having this problem, googling around and I was surprised to find my own thread.

Anyway, just tested your changes a year later and they work BEAUTIFULLY. THANK YOU SO MUCH!!!

1 Like