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 %}
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.
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.
Is it possible to do this in a way that completely omits data: from the command if the variable isn’t defined?
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 omitdata
. 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.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.
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/
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.
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.
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”
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 }}