I’m trying to get a script built. I want to check if a variable exist and include it if it does. Just really struggling to figure out the formatting. Something like

script:
  sequence:
    target:
      entity_id: "{{ entity }}"
    {% if variable is defined %}
      data: "{{ variable }}"
    {% endif %}
  • bob_wiley@lemmy.world
    link
    fedilink
    English
    arrow-up
    4
    ·
    edit-2
    10 months ago

    I haven’t used Home Assistant, but have done a lot of Ansible with yaml and jinja2, which looks similar enough that I assume that’s what’s going on here.

    If so, the if statement can’t go anywhere, and should be part of the value of the data key.

    So it would be more like…

    script:
      sequence:
        target:
          entity_id: "{{ entity }}"
          data: >-
            {% if variable is defined %}
              {{ variable }}
            {% endif %}
    

    The >- is to define a block and trim white space. More info on that here if you care https://yaml-multiline.info/

    The indentation and spacing also matters a lot.

    • Otkaz@lemmy.worldOP
      link
      fedilink
      English
      arrow-up
      2
      ·
      10 months ago

      Is it possible to do this in a way that completely omits data: from the command if the variable isn’t defined?

      • Otkaz@lemmy.worldOP
        link
        fedilink
        English
        arrow-up
        2
        ·
        edit-2
        10 months ago

        To give more context I’m working on a media control dashboard. The script or rather scripts I have to send commands to kodi is as follows

        kodi_control:
          sequence:
          - service: kodi.call_method
            target:
              entity_id: '{{ kodi_entity }}'
            data:
              method: '{{ kodi_method }}'
        
        kodi_control_playback:
          sequence:
          - service: kodi.call_method
            target:
              entity_id: '{{ kodi_entity }}'
            data:
              method: '{{ kodi_method }}'
              playerid: '{{ kodi_playerid }}'
        
        kodi_control_subtitles:
          sequence:
          - service: kodi.call_method
            target:
              entity_id: '{{ kodi_entity }}'
            data:
              method: '{{ kodi_method }}'
              action: '{{ kodi_action }}'
        
        kodi_control_seek:
          sequence:
          - service: kodi.call_method
            target:
              entity_id: '{{ kodi_entity }}'
            data:
              method: '{{ kodi_method }}'
              playerid: '{{ kodi_playerid }}'
              value: '{{ kodi_value }}'
        
        kodi_control_playlist:
          sequence:
          - service: kodi.call_method
            target:
              entity_id: '{{ kodi_entity }}'
            data:
              method: '{{ kodi_method }}'
              window: '{{ kodi_window }}'
              parameters: '{{ [ kodi_parameters ] }}'
        

        I would like to condense all of this down to a single script using “is defined” to omit the parts not needed for certain commands so something like

        kodi_control:
          sequence:
          - service: kodi.call_method
            target:
              entity_id: '{{ kodi_entity }}'
            data: >-
              method: '{{ kodi_method }}'
              {% if kodi_playerid is defined %}
                playerid: '{{ kodi_playerid }}'
              {% endif %}
              {% if kodi_action is defined %}
                action: '{{ kodi_action }}'
              {% endif %}
              {% if kodi_value is defined %}
                value: '{{ kodi_value }}'
              {% endif %}
              {% if kodi_window is defined %}
                window: '{{ kodi_window }}'
              {% endif %}
              {% if kodi_parameters is defined %}
                parameters: '{{ [ kodi_parameters ] }}'
              {% endif %}
        

        Problem with the above is I get “result is not a dictionary”

        • bob_wiley@lemmy.world
          link
          fedilink
          English
          arrow-up
          3
          ·
          10 months ago

          Ok, I think I got you. With your current setup, you’re not going to get the proper data structure, as it’s going to return all your key/value pairs as one big string. What you need to do here is create your empty dictionary, then add the key/value pairs, based on your logic, then return the resulting dictionary at the end.

          Something like this…

          kodi_control:
          sequence:
          - service: kodi.call_method
            target:
              entity_id: '{{ kodi_entity }}'
            data: >-
              {% set my_dict = {} %}
              {% set x=my_dict.__setitem__("method", {{ kodi_method }}) %}
              {% if kodi_playerid is defined %}
                {% set x=my_dict.__setitem__("playerid", {{ kodi_playerid }}) %}
              {% endif %}
              {% if kodi_action is defined %}
                {% set x=my_dict.__setitem__("action", {{ kodi_action }}) %}
              {% endif %}
              {% if kodi_value is defined %}
                {% set x=my_dict.__setitem__("value", {{ kodi_value }}) %}
              {% endif %}
              {% if kodi_window is defined %}
                {% set x=my_dict.__setitem__("window", {{ kodi_window }}) %}
              {% endif %}
              {% if kodi_parameters is defined %}
                {% set x=my_dict.__setitem__("parameters", {{ [ kodi_parameters ] }}) %}
              {% endif %}
              {{ my_dict }}
          
      • bob_wiley@lemmy.world
        link
        fedilink
        English
        arrow-up
        2
        ·
        edit-2
        10 months ago

        You can see if jinja filters work. Ansible has a bunch, but I’m not sure if it’s an Ansible thing or some of it is native to jinja. I know Ansible defines a lot of custom ones.

        Assuming it works, for what you’re doing it could be simplified to…

        script:
          sequence:
            target:
              entity_id: "{{ entity }}"
              data: "{{ variable | default(omit) }}"
        

        This basically says for data, use {{ variable }}, unless it doesn’t exist, in which case omit data. Omit could also be replaced with some another variable or static string (quoted) to use that as a default if {{ variable }} doesn’t exist.

        I tried quickly looking on the Home Assistant site to see if this would work and didn’t see anything, but if it’s anything like Ansible, the documentation leaves a lot of room for finding stuff through experience and leaning on other resources. I’d say try it and see what happens. That’s probably the fastest way to know if it will work.

        Depending on what data does here, you might be able to just add an else condition to set it to a blank string. That works better in some cases than others. I’m not sure if there is an “official” way to do this, but {{- '' -}} seems to work for me. I usually add those extra minus signs on everything when using jinja to avoid issues with extra spaces (those trim white space). If you don’t want to go the empty string route, or it doesn’t play well, you might be able to try NONE as well, as mentioned here.

        • Otkaz@lemmy.worldOP
          link
          fedilink
          English
          arrow-up
          1
          ·
          10 months ago

          It worked the same as your suggestion above. In cases the variable is used it does works as intended but in the situation the variable is not set it’s still sending data: just with a blank value.

          • bob_wiley@lemmy.world
            link
            fedilink
            English
            arrow-up
            1
            ·
            10 months ago

            hmm… It looks like default is a built-in jinja filter, either omit isn’t a built in option (which would make sense), or Home Assistant doesn’t play nice with it, or doesn’t support it. I’m guessing it’s a special Ansible add-on, as it requires the jinja to impact the yaml outside it (and there is also some artifacts I’ve seen that lend to that happening as well).

            https://jinja.palletsprojects.com/en/latest/templates/#jinja-filters.default

            Maybe you can refactor things a bit to only run this sequence when the variable exists?

            It looks like there are conditionals that can be added. I’m not sure if this will work for your specific use case or not, but it’s worth looking into if you haven’t already.

            https://www.home-assistant.io/docs/scripts/conditions/

            • Otkaz@lemmy.worldOP
              link
              fedilink
              English
              arrow-up
              1
              ·
              10 months ago

              When I tried playing with omit in the template editor I got an error about omit being undefined so probably not built in. Bummer because that would be a very elegant solution to this. I’m going to put this down for the night and try picking it back up tomorrow. I really appreciate all the suggestions. Hopefully it will lead me to a solution.

              • bob_wiley@lemmy.world
                link
                fedilink
                English
                arrow-up
                1
                ·
                10 months ago

                I looked at all the comments after I posted this and saw your full code. The suggestion I put there isn’t as nice as default(omit), but still probably much better than trying to go with this conditional route, which will probably increase code instead of reducing it. I think that should solve your problem. I didn’t really think about building the entire data payload on the fly until seeing your post, but it makes sense as a solution.

    • nottelling@lemmy.world
      link
      fedilink
      English
      arrow-up
      1
      ·
      10 months ago

      This looks like the right answer, since OP’s jinja is correct.

      OP, you can go to developer tools to test your template syntax against the live data in HA.