Monitor long your HVAC system runs per day or month

The template sensor should create a sensor that reports the current operational state, obtained from the climate entity of the thermostat. In the corrected configuration below that entity_id: will be sensor.test

The hvac_modes attribute of the climate entity only contains a list of supported operation modes, not the current operating state of the thermostat. Check for the existence of the attribute hvac_action and see what changes to when the thermostat calls for heat. Not all thermostat integrations may support hvac_action or properly update the status.

The history_stats sensor looks at sensor.test and measures the time its state is heat.

- platform: template
  sensors:
    test:
      friendly_name: test_test
      icon_template: mdi:radiator
      value_template: "{{ state_attr('climate.salon' , 'hvac_action' )}}"

- platform: history_stats
  name: "duree_de_chauffe"
  entity_id: sensor.test
  state: "heating"
  type: time
  # end today at 00:00:00
  end: "{{ now().replace(hour=0, minute=0, second=0, microsecond=0) }}"
  duration:
    hours: 24

I’m not sure what time period you are wanting to look at. I think your history_stats sensor will give you yesterday’s runtime, not today’s.

To get the run time starting at midnight today, the interval resetting every midnight


start: "{{ now().replace(hour=0, minute=0, second=0, microsecond=0) }}"
end: "{{ now() }}"

To get the usage continuously over a rolling 24 hour period, use the below.

   end: "{{ now() }}"
   duration: 
     hours: 24

Thanks a lot for the answer.

I use Netatmo.
If i see attributes :

So, i see the modes : auto, heat, off.
And i see hvac_action, who is heating now.

What i think, is that if i have “heat” in state of history stats, i just have the manual heat demand (manual boost on Netatmo). An no the heating period when the mode is auto.
I say that, because i see for yesterdayt 1,30H and i think that it isn’t all the heating duration of my house in the day.

If i have “heating” in state of the history stats, it doesn’t works. i have a 0 duration.

What do you think about that?

This is the code who works, but not sure i have all the heating duration for yesterday.

- platform: history_stats
  name: "temps_chauffage"
  entity_id: climate.salon
  state: "heat"
  type: time
  # end today at 00:00:00
  end: "{{ now().replace(hour=0, minute=0, second=0, microsecond=0) }}"
  duration:
    hours: 24

test:
        friendly_name: test_test
        icon_template: mdi:radiator
        value_template: "{{ state_attr('sensor.temps_chauffage' , 'hvac_action' )}}"

EDIT :
Here is my heating report for yesterday :

Like i said, and as you can see, there is few hours in the day with heating. But it is “auto” heating.

And because of my tests, only 1H30 of manual heating, which is the value given by the history-stats

RE-EDIT

When i am on auto mode (schedule), and when there is a heating demand, i see in the attributes :

hvac_action: heating
preset_mode: Schedule

May me is it possible to combine the 2 values?

Like : give me the heatng duration in manual mode (it works) and the heating duration when hvac_action is “heating” and preset_mode is “Schedule”.

But i don’t know how to do that.

What do you think ?

The state of climate.salon will be only be auto,heat or off. It doesn’t tell you when the unit is actually heating. It only tells you if the unit will heat when it gets too cold or if it is completely turned off. It won’t help you find how much energy it using.

You need to use the state of sensor.test with history_statistics to tell exactly when the unit is running. The states should be.

  • heating – The unit is currently heating and using electricity/gas to heat the air.
  • idle – The unit is currently not heating
  • off – The unit is completely turned off

Try the following configuration
 If you turn the heat up, you should see a change in heating duration almost immediately.

- platform: template
  sensors:
    test:
      friendly_name: test_test
      icon_template: mdi:radiator
      value_template: "{{ state_attr('climate.salon' , 'hvac_action' )}}"

- platform: history_stats
  name: "duree_de_chauffe"
  entity_id: sensor.test
  state: "heating"
  type: time
  end: "{{ now() }}"
  duration:
    hours: 24

Thanks a lot Eric. I understand perfecly the way.

But it doesn’t works, i’m sorry.

Even if i stop the heat, and turn on the heat. The sensor’s value stay at 0.

My actually code

     temps_chauffage2:
        friendly_name: temps_chauffage2
        icon_template: mdi:radiator
        value_template: "{{ state_attr('climate.salon', 'hvac_action' )}}"

- platform: history_stats
  name: "temps_chauffage2"
  entity_id: sensor.temps_chauffage2
  state: "heating"
  type: time
  start: "{{ now().replace(hour=0, minute=0, second=0, microsecond=0) }}"
  end: "{{ now() }}"
1 Like

I have the exact same situation. did you manage a fix?

Update: its working for me now with this config

- platform:  history_stats
  name:  "hvac_run_time"
  entity_id:  sensor.hvac_state
  state:  "heating"
  type:  time
  end:  "{{ now() }}"
  duration:
    hours: 24

I am very new to getting HA working in my production home environment.

I am using a Radio Thermostat CT-50, using the information in this helpful thread,

I have added this block in my configuration.yaml

recorder:  
  purge_keep_days: 365
# HVAC On/Off time Tracking
binary_sensor:
  - platform: template
    sensors:
      hvac_heat:
        friendly_name: "HVAC Heat"
        value_template: >-
          {{ is_state_attr('climate.home', 'hvac_action', 'heating') }}
  - platform: template
    sensors:
      hvac_cool:
        friendly_name: "HVAC Cool"
        value_template: >-
          {{ is_state_attr('climate.home', 'hvac_action', 'cooling') }}
# HVAC History Tracking
sensor:
  - platform: history_stats
    name: Daily Heating ON Time
    entity_id: binary_sensor.hvac_heat
    state: 'on'
    type: time
    start: '{{ now().replace(hour=0).replace(minute=0).replace(second=0) }}'
    end: '{{ now() }}'
  - platform: history_stats
    name: Hourly Cooling ON Time
    entity_id: binary_sensor.hvac_cool
    state: 'on'
    type: time
    start: '{{ now().replace(minute=0).replace(second=0) }}'
    end: '{{ now() }}'

This is my state info from the developers tab:

I did not get any errors when I verified the yaml and reloaded


Now how do I check if the sensor is actually working?
View a graph of the logged data over time?

Thanks for that code. Worked like a charm for me. Though I had to make a slight modification. My system (cool/heat/off) and fan (on/auto/circulate/off) are separate (Honeywell). I have my fan set to circulate which works regardless of the system operation. So when it is off, the fan can still circulate air.
Here’s the updated code to take that into account. (does check for fan twice. As when it’s off, the hvac_action is idle, but fan_action is running. But if it’s heating, the hvac_action is heat/cool, so I don’t want to capture that with a fan_action in the initial if ‘off’ statement)

basement_status:
        friendly_name: "Basement Climate Status"
        value_template: >-
          {%- if is_state('climate.basement', 'off') %}
            {% if is_state_attr('climate.basement', 'fan_action', 'running') %}
              fan
            {% else %}
              off
            {% endif %}
          {% elif is_state_attr('climate.basement', 'hvac_action', 'fan') %}
            fan
          {% elif is_state_attr('climate.basement', 'hvac_action', 'idle') %}
            idle  
          {% elif is_state_attr('climate.basement', 'hvac_action', 'cooling') %}
            cool
          {% elif is_state_attr('climate.basement', 'hvac_action', 'heating') %}
            heat
          {% else %}
            unknown
          {%- endif %}
        icon_template: >-
          {% if is_state('sensor.basement_status',"idle") %}
            mdi:power-on
          {% elif is_state('sensor.basement_status',"cool") %}
            mdi:snowflake
          {% elif is_state('sensor.basement_status',"heat") %}
            mdi:fire
          {% elif is_state('sensor.basement_status',"fan") %}
            mdi:fan
          {% else %}
            mdi:octagon
          {% endif %}