Syntax for if else template statement in a file

I have read this and this but I am new to YAML and so I might be missing something simple here.

I am trying to add a new sensor to my template.yaml !included file. There are loads of sensors in there which work fine already.

This works fine - I have 20 / 30 of these.

- sensor:
  - name: front_hall_current_temperature
    unique_id: front_hall_current_temperature
    unit_of_measurement: '°C'
    icon: mdi:thermometer
    state: "{{ state_attr('climate.front_hall', 'current_temperature') | float(0) }}"

The new sensor type has to evaluate a mode state before returning querying a value - the reason is the value won’t be there if the mode is “TemporaryOverride” and another value is required as per code below.

developer > test code

      {% if state_attr('climate.front_hall', 'status').setpoint_status.setpoint_mode == 'TemporaryOverride' %}
        {{ state_attr('climate.front_hall', 'status').setpoint_status.target_heat_temperature | float(0) }}
      {% else %}
        {{ (state_attr('climate.front_hall', 'status').setpoints.this_sp_temp) | float(0) }}
      {% endif %}

Produces “15°C” - correctly.

Also same code pasted into a helper UI → template → sensor template - works fine and returns the same integer no problem.

However I can’t get this sensor to show up after restarting HA when I write it into the templates.yaml file. All the other sensors in the file appear in helpers a ok.

- sensor:
  - name: front_hall_target_temperature
    uniqe_id: front_hall_target_temperature
    unit_of_measurement: '°C'
    icon: mdi:thermometer
    state: >-
      {% if state_attr('climate.front_hall', 'status').setpoint_status.setpoint_mode == 'TemporaryOverride' %}
        {{ state_attr('climate.front_hall', 'status').setpoint_status.target_heat_temperature | float(0) }}
      {% else %}
        {{ (state_attr('climate.front_hall', 'status').setpoints.this_sp_temp) | float(0) }}
      {% endif %}

I am sure its some syntax error on my part but I have tried permutations of > / >- / etc and read the yaml specs and the jinja help as well and I can’t see where I am going wrong. It’s confusing becuase it works fine in the test tools as I say. Sorry if this is something obvious!

What does the template editor return for:

state_attr('climate.front_hall', 'status').setpoint_status.setpoint_mode

The template editor is a bit more lax when it comes to undefined/nonexistent variables. If setpoint_status or setpoint_mode aren’t always defined, you will need to check that before comparing the value.

Are you seeing anything in the home-assistant.log?

One other idea. Check the history of climate.front_hall’s state. Does it go to “unavailable” or “unknown” at the moments where you restart HA?

Just a string - at the moment the if statement will evaluate false - which is expected to drop into the else condition.

It could be that - actually. How might I deal with that - in fact (sorry I am new to HA) I think I have seen something about dealing with unavailable states during restarts. ??

It depends on what you want your template sensor to report when climate.front_hall is one of those. But yes, if that’s what’s happening, then as soon as the state changes to one of those two, the sensor will throw an error because a string won’t have the setpoint_status member.

You can use has_value('climate.front_hall') to determine whether it’s unavailable or unknown and adjust your logic.

Also, look into availability_template if you’d like your template sensor to go unto ‘unavailable’ when climate.front_hall is unavailable, which will prevent recomputing the value in that state.

Are you seeing anything in the home-assistant.log?

Nothing in the logs no.

You might find this discussion about availability templates helpful, even though it’s in the first instance geared towards energy consumption.

It comes from the HA Cookbook, which is another link you might want to have handy.

Ah yes that is cool! thank you so much - frantically working through has_value syntax - with little success. The variables are wrapped in sub structures so the syntax isn’t simple and I am learning the language.

Note that has_value only works on entities–it tells you if the entity you pass it has a state that is something other than “unavailable” or “unknown”. So, has_value('climate.front_hall') returns true if the state of that entity is something other than “unavailable” or “unknown.”

You aren’t directly referencing the state of that entity, but an attribute of it called status. You can’t apply has_value to test attributes.

In fact, using has_value here can help you avoid referencing setpoint_status when the state of climate.front_hall is “unavailable” or “unknown,” which is probably a proxy to tell whether the status attribute has the values you’re expecting. But that may or may not be fair a assumption.

Say that climate.front_hall has a known state, so has_value('climate.front_hall') returns true. You can do further error-checking to make sure that the attribute status has the structure you’re expecting with something like:

      {% if has_value('climate.front_hall') %}
        {% 
           if state_attr('climate.front_hall', 'status').setpoint_status is defined
                and
              state_attr('climate.front_hall', 'status').setpoint_status.setpoint_mode is defined
         %}

           {% if state_attr('climate.front_hall', 'status').setpoint_status.setpoint_mode == 'TemporaryOverride' %}
             {{ state_attr('climate.front_hall', 'status').setpoint_status.target_heat_temperature | float(0) }}
           {% elif state_attr('climate.front_hall', 'status').setpoints is defined %}
             {{ (state_attr('climate.front_hall', 'status').setpoints.this_sp_temp) | float(0) }}
           {% else %}
             {# Up to you how you want to handle this condition... #}
           {% endif %}

      {% else %}
        {# Up to you how you want to handle this condition... #}
      {% endif %}

If you correctly use has_value in the availability_template, you probably won’t need the first-level if has_value('climate.front_hall') and associated else.

Yeah - so actually it is the “until” value which is not present when the mode is NOT == “TemporaryOverride”

So is it that which I need to query - not target_temperature.
In this image TemporaryOveride has been set true for the zone so the until attribute is present.

The time the temporary override completes is important understand when glancing through the state of the system in the UI, I have yet to build.

It’s a fair bit to process so I may come back to this in the morning.

Sheesh !!!

miss-spelled unique - that was all it was !

I am going to mark your post as the solution since there was such allot of really helpful and useful info in there - all of which could have been valid issues !

1 Like

In general, I strongly recommend checking for dictionary keys before trying to get their values. Integrations change sometimes or encounter states you didn’t hit during development, and it can be very difficult to debug things like this.

Absolutely understood and thank you again…

I liked the .get() approach you had originally posted; I just couldn’t respond at the time. Glad it’s working!

It didn’t work - but this does.

      {% set status = state_attr('climate.front_hall', 'status') %}
      {% if status is not none and 'setpoint_status' in status and 'target_heat_temperature' in status.setpoint_status %}
        {{ status.setpoint_status.target_heat_temperature }}
      {% else %}
        unavailable
      {% endif %}