Intermittent TypeError from Automation

Hi, I have written a couple of automations, the purpose of which is to get a temperature from a sensor in the middle of a room (the sensor.xiaomi_*) and pass it onto a ZWave thermostatic valve as a temperature offset so that the valve knows what the real temperature is.

Most of the time it works, but sometimes is bombs out with TypeErrors comparing strings and floats

Logger: homeassistant.components.automation.correct_trv_kids_temp
Source: helpers/script.py:1156
Integration: Automation (documentation, issues)
First occurred: 16:22:00 (4 occurrences)
Last logged: 17:05:57

Heating: Correct TRV Kids Temp: Error executing script. Error for call_service at pos 1: Error rendering data template: TypeError: unsupported operand type(s) for -: 'str' and 'float'

The template syntax inside YAML is driving me crazy when there are multiline expressions with logic involved, so I am a bit lost with where I am messing up with variable classes. Any hints on how to correct/debug this very much appreciated. Here is the code for the whole thing:

id: auto_trv_kids_correction
  alias: "Heating: Correct TRV Kids Temp"
  description: Correct TRV Kids Temperature to that given by room Xiaomi thermometer
  trigger:
    - platform: state
      entity_id: sensor.trv_kids_air_temperature
    - platform: state
      entity_id: sensor.xiaomi_kids_temperature
  condition:
    - condition: state
      entity_id: input_boolean.heating_season
      state: "on"
  action:
    - service: input_number.set_value
      target:
        entity_id: input_number.kids_temperature_correction
      data:
        value: >
          {## Read room temp from sensor and from TRV. Calculate difference ##}
          {% set sensor_temp = float(states('sensor.xiaomi_kids_temperature')) %}
          {% set trv_temp = float(states('sensor.trv_kids_air_temperature')) %}
          {% set old_correction = float(states('input_number.kids_temperature_correction')) %}
          {% set corr = [-5,(sensor_temp - trv_temp + old_correction)]|max %} 
          {% set corr= [5,corr]|min %} 
          {{ '%0.1f'|format(corr) }}
    - service: zwave_js.set_config_parameter
      data:
        parameter: "8"
        value:  >
          {## This takes the above temp corr, multiplies by 10 and passes ##}
          {## to the config param ##}   
          {% set corr = 10*float(states('input_number.kids_temperature_correction'))  %}  
          {{'%0.0f'|format(corr)}}
      target:
        device_id: 90baba58a787d67149e4371cfa26d9cf
  mode: restart

Observe how float behaves when used as a function versus a filter:

When one of your sensors is unavailable, the float() function doesn’t convert it to a zero but leaves it as a string. This line tries subtracting a mix of strings and numbers:

{% set corr = [-5,(sensor_temp - trv_temp + old_correction)]|max %} 

Which results in the error message:

TypeError: unsupported operand type(s) for -: ‘str’ and ‘float’


EDIT

What was left unsaid: Change the usage of float from function call to filter.

          {% set sensor_temp = states('sensor.xiaomi_kids_temperature') | float %}
          {% set trv_temp = states('sensor.trv_kids_air_temperature') | float %}
          {% set old_correction = states('input_number.kids_temperature_correction') | float %}

It may be that sometimes either states('sensor.xiaomi_kids_temperature') or states('sensor.trv_kids_air_temperature') returns something other than a numeric value (e.g., ‘unknown’ or ‘unavailable’). In that case, the float function will return the string. I.e.,

{{ float('unavailable') }}

will return 'unavailable', which is a string. And you can’t use the subtraction operator with one operand being a string and the other being a number.

Generally it’s better to use the float filter instead of the float function. The float filter will return a default value if its argument is not a numeric value. The default default is zero, but you can specify a different default. E.g., you could use one of these:

|float
|float(100)

as in:

          {% set sensor_temp = states('sensor.xiaomi_kids_temperature')|float %}
          {% set trv_temp = states('sensor.trv_kids_air_temperature')|float %}

But, really, if either of these are not a numeric value, it’s probably better not to do anything. So maybe:

id: auto_trv_kids_correction
  alias: "Heating: Correct TRV Kids Temp"
  description: Correct TRV Kids Temperature to that given by room Xiaomi thermometer
  trigger:
    - platform: state
      entity_id:
        - sensor.trv_kids_air_temperature
        - sensor.xiaomi_kids_temperature
  variables:
    sensor_temp: "{{ float(states('sensor.xiaomi_kids_temperature')) }}"
    trv_temp: "{{ float(states('sensor.trv_kids_air_temperature')) }}"
  condition:
    - condition: state
      entity_id: input_boolean.heating_season
      state: "on"
    - condition: template
      value_template: "{{ sensor_temp is number and trv_temp is number }}"
  action:
    - service: input_number.set_value
      target:
        entity_id: input_number.kids_temperature_correction
      data:
        value: >
          {## Read room temp from sensor and from TRV. Calculate difference ##}
          {% set old_correction = states('input_number.kids_temperature_correction')|float %}
          {% set corr = [-5,(sensor_temp - trv_temp + old_correction)]|max %} 
          {% set corr= [5,corr]|min %} 
          {{ '%0.1f'|format(corr) }}
    - service: zwave_js.set_config_parameter
      data:
        parameter: "8"
        value:  >
          {## This takes the above temp corr, multiplies by 10 and passes ##}
          {## to the config param ##}   
          {% set corr = 10*float(states('input_number.kids_temperature_correction'))  %}  
          {{'%0.0f'|format(corr)}}
      target:
        device_id: 90baba58a787d67149e4371cfa26d9cf
  mode: restart

That’s great! Thanks a lot. If I knew about “variables” I would have written a bunch of my scripts differently.

So did changing how float is used (as a filter instead of a function) eliminate the error message?

Indeed it seems to have. It’s been running for the day with no error so far and the temperatures properly adjusted. Hopefully it’s done.

Thanks a lot!