Furnace filter runtime sensor (now includes a version for HASS ≥0.96)

Click here for HASS versions older than 0.96 (deprecated)

Click here for HASS versions ≥0.96.

This package uses the input_text and input_number integrations, template sensors, a script, history stats sensors, and an automation to track and display the total HVAC runtime since the furnace filter was last changed. It also calculates an estimate of the number of days until your filter will need to be changed. History stats are great, but they’re limited to what you have purge_keep_days set to in recorder . This package only requires one day of history to record runtime and seven days to calculate remaining runtime based on a rolling seven-day average.

  • The furnace_filter input_text is a time/date string and is used to record when the filter was last changed.
  • The hvac_runtime input_number stores the total runtime since the filter was last changed.
  • The replacement_threshold input_number is used to set the number of hours that you expect the filter to last. I like sliders, but you can of course change the configuration to box if you prefer to type out a number.
  • The script sets furnace_filter to the current date/time and resets hvac_runtime . You can call this script in an entity button in your frontend to conveniently reset everything after you change the filter.
  • The history stats sensors record the amount of time (in hours) that the system has been heating/cooling starting at midnight on the day the filter was changed and ending at the time the filter was changed. This is used to not double-count runtime when the filter is marked as changed and hvac_runtime is updated. Some are also used to calculate a rolling seven-day average to determine approximately how many days are remaining until the next filter change will be required. The value that replacement_threshold is set to is used in this calculation.
  • The hvac_action template sensor is required for HASS versions 0.96 and newer to allow the history stats sensors to track heating/cooling runtime due to changes in the Climate component. NOTE: You’ll need to change the entity ID in this sensor to match your thermostat entity ID, otherwise this won’t work.
  • A template sensor adds the value in hvac_runtime and the heating/cooling runtime for the current day, and an automation runs each night to update hvac_runtime with this value so that the total runtime is permanently stored.
2 Likes

Hey,
I tried to put this into my system but get the following error in my log: Parsing error: end must be a datetime or a timestamp. Config check doesn’t report any issues.

Which version are you using? Pre-0.96 or 0.96 and newer?

Hmm. Well that’s definitely weird, everything’s working ok on my end. Could you please provide the full detail of that error message?

This is all the error logging I get:

2020-01-17 22:52:25 ERROR (SyncWorker_10) [homeassistant.components.history_stats.sensor] Parsing error: end must be a datetime or a timestamp

Looks like the solution I am looking for! How hard would it be for me to modify it to track to separate AC units?

Unfortunately you’d need to duplicate the package for each AC unit you want to track (and rename each piece accordingly). You probably don’t need to duplicate the replacement_threshold input_number though, and you could just add additional service calls to the automation instead of duplicating that. Doesn’t save much work though :confused:

Thank you…Started working on this now, and will update when I get them both knocked out. Another question before I get much deeper…

in the below, I removed the “<” from “furnace_filter_days_remaining:” to allow me to use a gauge card. I read through the code a few times, and I dont see where that would break anything…but its your baby…thoughts?

  # Calculate number of days until filter will need to be changed based on replacement threshold and rolling average
    furnace_filter_days_remaining:
      friendly_name: "Furnace filter days remaining"
      value_template: >
        {% if (states('sensor.average_total_runtime_week') | int) == 0 %}
          30
        {% elif ((((states('input_number.replacement_threshold') | float) - (states('sensor.furnace_filter_life') | float)) / (states('sensor.average_total_runtime_week') | float)) | round(0)) > 30 %}
          30
        {% else %}
          {{ (((states('input_number.replacement_threshold') | float) - (states('sensor.furnace_filter_life') | float)) / (states('sensor.average_total_runtime_week') | float)) | round(0) }}
        {% endif %}
      unit_of_measurement: 'd'

Should be fine. I just did that to prevent a divide by zero error or having it display a ridiculous number of days (such as when average weekly runtime is very little).

If I were better with Python I’d try to make this a custom integration to make it easier for situations involving more than one thermostat, but I’m not quite there yet…

I had this same issue. I think it was because I had no value for input_text.furnace_filter. Once I set that, the error went away and it seems to be working.

The float function was revised in release 22.10.0 to require the default to be specified. Previously it would have been set to zero.

I’d suggest this revision

service: input_number.set_value
entity_id: input_number.hvac_runtime
data_template:
  value: >-
    "{{ ((states('sensor.furnace_filter_life') |float(0)) +
    (states('sensor.cooling_time_yesterday') |float(0)) +
    (states('sensor.heating_time_yesterday') |float(0))) | round(1) }}"

@Tediore, I’m attempting to use the Furnace Filter Runtime Sensor but I’m seeing errors each time HA is restarted. The errors are;

2023-04-24 21:56:21.336 ERROR (MainThread) [homeassistant.components.history_stats.helpers] Error parsing template for field end
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 1784, in forgiving_as_timestamp
return dt_util.as_timestamp(value)
File "/usr/src/homeassistant/homeassistant/util/dt.py", line 134, in as_timestamp
raise ValueError("not a valid date/time.")
ValueError: not a valid date/time.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 539, in async_render
render_result = _render_with_context(self.template, compiled, **kwargs)
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 2130, in _render_with_context
return template.render(**kwargs)
File "/usr/local/lib/python3.10/site-packages/jinja2/environment.py", line 1301, in render
self.environment.handle_exception()
File "/usr/local/lib/python3.10/site-packages/jinja2/environment.py", line 936, in handle_exception
raise rewrite_traceback_stack(source=source)
File "<template>", line 1, in top-level template code
File "/usr/local/lib/python3.10/site-packages/jinja2/sandbox.py", line 393, in call
return __context.call(__obj, *args, **kwargs)
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 1787, in forgiving_as_timestamp
raise_no_default("as_timestamp", value)
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 1589, in raise_no_default
raise ValueError(
ValueError: Template error: as_timestamp got invalid input 'unknown' when rendering template '{{ as_timestamp(states('input_text.furnace_filter')) }}' but no default was specified
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/components/history_stats/helpers.py", line 39, in async_calculate_period
rendered = template.async_render()
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 541, in async_render
raise TemplateError(err) from err
homeassistant.exceptions.TemplateError: ValueError: Template error: as_timestamp got invalid input 'unknown' when rendering template '{{ as_timestamp(states('input_text.furnace_filter')) }}' but no default was specified
2023-04-24 21:56:21.340 ERROR (MainThread) [homeassistant.components.history_stats.coordinator] Error fetching Cooling before last filter change data: ValueError: Template error: as_timestamp got invalid input 'unknown' when rendering template '{{ as_timestamp(states('input_text.furnace_filter')) }}' but no default was specified
2023-04-24 21:56:21.350 ERROR (MainThread) [homeassistant.components.history_stats.helpers] Error parsing template for field end
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 1784, in forgiving_as_timestamp
return dt_util.as_timestamp(value)
File "/usr/src/homeassistant/homeassistant/util/dt.py", line 134, in as_timestamp
raise ValueError("not a valid date/time.")
ValueError: not a valid date/time.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 539, in async_render
render_result = _render_with_context(self.template, compiled, **kwargs)
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 2130, in _render_with_context
return template.render(**kwargs)
File "/usr/local/lib/python3.10/site-packages/jinja2/environment.py", line 1301, in render
self.environment.handle_exception()
File "/usr/local/lib/python3.10/site-packages/jinja2/environment.py", line 936, in handle_exception
raise rewrite_traceback_stack(source=source)
File "<template>", line 1, in top-level template code
File "/usr/local/lib/python3.10/site-packages/jinja2/sandbox.py", line 393, in call
return __context.call(__obj, *args, **kwargs)
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 1787, in forgiving_as_timestamp
raise_no_default("as_timestamp", value)
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 1589, in raise_no_default
raise ValueError(
ValueError: Template error: as_timestamp got invalid input 'unknown' when rendering template '{{ as_timestamp(states('input_text.furnace_filter')) }}' but no default was specified
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/components/history_stats/helpers.py", line 39, in async_calculate_period
rendered = template.async_render()
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 541, in async_render
raise TemplateError(err) from err
homeassistant.exceptions.TemplateError: ValueError: Template error: as_timestamp got invalid input 'unknown' when rendering template '{{ as_timestamp(states('input_text.furnace_filter')) }}' but no default was specified
2023-04-24 21:56:21.353 ERROR (MainThread) [homeassistant.components.history_stats.coordinator] Error fetching Heating before last filter change data: ValueError: Template error: as_timestamp got invalid input 'unknown' when rendering template '{{ as_timestamp(states('input_text.furnace_filter')) }}' but no default was specified

I’m running;

Home Assistant 2023.4.6
Supervisor 2023.04.1
Operating System 10.0
Frontend 20230411.1 - latest

with Furnace filter runtime sensor version 0.96. Appreciate the sensor is a couple of years old and that there’s been many changes to HA since the sensors inception. I’ve looked through the code, found the offending lines but do not know how to adjust the code to correct the error.

Would you kindly point me in the correct direction?

With appreciation.

I was encountering this issue myself and after looking at the code and how the data was entered into the field it looks like the issue is the format of the date being entered into the “input_text.furnace_filter” field itself. I entered my data as 01/05/2023 and this used to work before some recent version of HA (I’m not exactly sure when it broke, but probably <2023.x). I have since updated the value in that field to be 2023-01-05 and the as_timestamp() function began working properly without needing to modify any code.

You can experiment with this in your developer tools on your instance with this code:

{{ as_timestamp(states('input_text.furnace_filter'),'0') }}

While my input had the common American formatting (MM-DD-YYYY) this would cause the output to be zero because the formula was failing and falling back to the default ‘0’. Since this script doesn’t have a fallback value in the code it results in an error message. As soon as I changed the format to the more common European format (YYYY-MM-DD) it started working correctly.