Correct way to return unknown / none from template sensor?

I have a REST sensor that is somewhat flaky due to the server being buggy. I would rather have my computed sensor return unknown / None than a bogus value so I can see gaps in the graph rather than incorrect zeros or whatever. I have tried a lot of different approaches to getting a template sensor to correctly return nothing. This is what I’m trying at the moment but I’d like to know if there is an idiom for returning a safe / correct unknown value.

I know that if the value itself is unknown that state_attr() will return ‘unknown’ but there are an essentially infinite number of possible garbage values that could be returned by the server that won’t yield ‘unknown’ e.g., if the server sends back HTML the response could be something like <HTML><BODY>whatever... so I’m testing the actual value with a regex and only want to return a real value if the regex matches.

    sensors:
      openevse_session_energy_raw:
        friendly_name: "OpenEVSE Session Energy (status)"
        icon_template: mdi:gauge
        unit_of_measurement: 'kWh'
        entity_id:
          - sensor.openevse_status
        value_template: >-
          {%- if state_attr('sensor.openevse_status', 'wattsec') | regex_match('[0-9]+') -%}
            {%- set wattsec = state_attr('sensor.openevse_status', 'wattsec') -%}
            {{- (wattsec|float / 3600000)|round(2) -}}
          {%- else -%}
            {{- None -}}
          {%- endif -%}

This seems like it ought to work, but I find that if I try to use this template as input into a filter sensor, it fails to initialize.


2019-05-19 14:25:20 ERROR (MainThread) [homeassistant.core] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/homeassistant/helpers/entity_platform.py", line 363, in _async_add_entity
    await entity.async_added_to_hass()
  File "/usr/local/lib/python3.7/site-packages/homeassistant/components/filter/sensor.py", line 223, in async_added_to_hass
    self._entity, prev_state, state, False)
  File "/usr/local/lib/python3.7/site-packages/homeassistant/components/filter/sensor.py", line 157, in filter_sensor_state_listener
    filtered_state = filt.filter_state(copy(temp_state))
  File "/usr/local/lib/python3.7/site-packages/homeassistant/components/filter/sensor.py", line 334, in filter_state
    filtered = self._filter_state(FilterState(new_state))
  File "/usr/local/lib/python3.7/site-packages/homeassistant/components/filter/sensor.py", line 409, in _filter_state
    if self.states else 0
  File "/usr/local/lib/python3.7/statistics.py", line 376, in median
    data = sorted(data)
TypeError: '<' not supported between instances of 'str' and 'float'

I’ve tried a few different approaches like returning a string ‘unknown’ or just leaving the else clause completely out so the expression returns nothing.

In all the cases I can come up with the filter still fails as above, of course I can return 0.0 and have the filter function, but I don’t really want to send bogus data to the filter at all.

Ideally the template sensor would eat the bad state change completely rather than sending bad data to listeners.

1 Like

Some things to consider…

First, do you know that state_attr('sensor.openevse_status', 'wattsec') is always a string? Although states are always strings, attributes can be any type.

regex_match will return true if only the beginning of the string matches the expression. E.g., '123xxx' | regex_match('[0-9]+') is true.

You probably should not return None. At the very least, it won’t be a Python None, it will be converted to a string (like all state values), so it will be 'None'. I’d recommend returning unknown. And, BTW, you can do that just with the word unknown (i.e., you don’t need the {{ ... }}.)

What might be easier (if you know good values are always non-negative) is to do something like this:

    sensors:
      openevse_session_energy_raw:
        friendly_name: "OpenEVSE Session Energy (status)"
        icon_template: mdi:gauge
        unit_of_measurement: 'kWh'
        value_template: >
          {% set wattsec = state_attr('sensor.openevse_status', 'wattsec')
                           |float(-1) %}
          {% if wattsec >= 0 %}
            {{ (wattsect / 3600000)|round(2) }}
          {% else %}
            unknown
          {% endif %}

The float(-1) filter will return the specified default value (-1) if the input cannot be converted to a float.

BTW, you don’t need all those dashes for this. And you also don’t need to use the entity_id option since it can find the entity_id automatically.

1 Like

‘{{ “unknown” if not states.sensor… else … }}’

I have a similar issue.
I have an MQTT sensor and a template sensor. I need the template sensor because I’ve calibrated the MQTT sensor - I need to subtract 1.

The problem is that sometimes my MQTT return unknown and my heating system is working all the time :confused:

temperatura_korytarz:
  friendly_name: "Korytarz"
  unit_of_measurement: '°C'
  value_template: >
    {{ states.sensor.korytarz_temperature.state | float - 1.0 }}

this is my current setup. So if states.sensor.korytarz_temperature.state is unknown, then the sensor return -1 as the current temperature and the heater is working and working.

temperatura_salon:
  friendly_name: "Salon"
  unit_of_measurement: "°C"
  value_template: >
    {%  if states.input_number.temp2 and states.input_number.temp2.state != "unknown" %}
    {{ states.input_number.temp2.state | float -1 }}
    {% else %}
    unknown
    {% endif %}

This is the second version that checks if the MQTT sensor is returning a valid value and then it is subtracting 1.

I’ve tried applying your pattern, but I don’t know how to do that. Can you advise me on this? Can the template be shorter?

1 Like
temperatura_salon3:
  friendly_name: "Salon"
  unit_of_measurement: "°C"
  value_template: "{{ 'unknown' if is_state('input_number.temp2', 'unknown') else states.input_number.temp2.state | float - 1 }}"

I think this should work just fine :slight_smile:

device_power:
  value_template: "{{ state_attr('switch.device','current_power_w')|float('Unknown') }}"
  unit_of_measurement: "W"
3 Likes