Over-engineering my Home Assistant HVAC Dashboard

Ever wondered how well your HVAC system is working in your home or condo? I did to an unhealthy degree. I want to know not just what’s the temperature, but how often is it running, what’s the supply and return temperatures, etc.? Let’s overengineer another project.

To start, I’ve got an Ecobee thermostat and use Home Assistant to integrate with all my devices. Home Assistant is an open-source smart-home orchestration system. It has numerous different integrations, which allow you to add almost any smart home device you can think of. I switched to after trying both Samsung SmartThings and Hubitat and finding of them not powerful.

Why?

With any thermostat added in Home Assistant, you can obviously know what is the temperature and humidity in different rooms and that’s useful, but HVAC units have a lot of different things that can be monitored.

For example, comparing the return temp (the temperature of the air going into the system) and the supply temp (air temp going back to your house) tells you how much the unit is able to increase or lower the temperature of the air.

Monitoring how long it runs per day helps me know whether it’s under sized or the setpoint is too low/high. I can even use this to know that I need to replace the filter after a certain number of hours of runtime.

My condo has a water sourced heat pump with a central water loop. When heating, it takes heat out of the loop and heats the air. When cooling, it takes heat in the air and transfers it to the water in the loop to go to the cooling tower up top. I attached a thermocouple to the pipe to measure that loop temp since it fluctuates based on how many other people are using it.

Home Assistant

First, add the thermostat to Home Assistant if it already isn’t already there. I’m using an Ecobee. If you have a different thermostat, you should still be able to use these dashboards, but you’ll need to ensure your thermostat provides similar sensors

Ecobee HomeKit

If you’ve got an Ecobee, then adding it using the Apple HomeKit Device integration will use local only network connections and avoid any cloud calls.

A screenshot from Home Assistant showing the HomeKit Device integration added

Ecobee Cloud Integration

There is also an Ecobee integration, but Ecobee stopped allowing people to sign up for the developer accounts. There’s a few features that the HomeKit integration doesn’t support like better mode switching because the HomeKit mode doesn’t set an override like the Ecobee integration does. I have both added, but disabled polling so I only make API calls when calling actions.

Basic Dashboards

Now, I’ve got some basic entities that report temperature, humidity, even motion. How you design your dashboard is up to your personal preference and the later metrics are more interesting. Don’t spend too much time here.

Motion

Ecobee thermostats and the smart reports report motion making them useful for motion tracking. A history graph makes it easy to see this across different rooms: And the YAML:

1
2
3
4
5
6
7
8
9
type: history-graph
entities:
  - entity: binary_sensor.home_motion
    name: Living Room
  - entity: binary_sensor.living_room_motion
    name: Office
  - entity: binary_sensor.bedroom_motion
    name: Bedroom
title: Motion

Thermostat Control

What dashboard isn’t complete without actually allowing us to edit the set points.

1
2
3
4
type: thermostat
entity: climate.home
features:
  - type: climate-hvac-modes

Calculating Runtime

Let’s get into the more complex metrics–runtime. Tracking runtime is a useful metric because it gives you some interesting insights:

  • Runtime - The more your A/C runs, the more wear it has and the more likely it’ll break down. You could use this to decide to schedule a yearly maintenance/inspection sooner or later depending on how much you use it.
  • Duty Cycle is the percentage of time that your unit is actually running. 100% means it’s running continuously. It could mean different things including: it’s a very hot/cold day, poor house insulation, improper setpoints, undersized HVAC units, or even a window left open.
  • Runtime since the filter was changed. As filters get dirtier, it gets harder to pull air through it making your system work harder. Tracking this gives you a metric to know when to replace your filter.

State Tracking

First, we’ll need to create a few template sensors to break out the states. You can either put this into your Home Assistant’s /config/configuration.yaml file, or create these using the UI in Settings > Devices & services > Helpers > Create Helper.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
template:
  - binary_sensor:
    # binary_sensor.hvac_fan_state
    # This tracks whether the fan is running
    # The fan will be running when it's in heat/cool or just running the fan
    # It tracks the unit actually working
    - name: "HVAC Fan State"
      icon: mdi:fan
      unique_id: 0k79upwzyOUladHiSg3R
      availability: "{{ has_value('climate.home') }}"
      state: >
        {{ (state_attr("climate.home", "hvac_action") in ["heating", "cooling", "fan"]) }}
  - sensor:
      # sensor.hvac_run_state
      # This tracks what the unit is doing, whether heating, cooling, or just spinning the fan
      - name: "HVAC Run State"
        unique_id: NtHeqUZpB2caZAA8PQyz
        availability: "{{ has_value('climate.home') }}"
        state: "{{ state_attr('climate.home', 'hvac_action') }}"

If you’re using YAML, save the file, then reload your entities in Developer tools >YAML tab > Reload “Template Entities” if it’s available, or restart HA if it’s not. You should now be able to see those new entities (Search in the top right if you don’t know where they are). If they’re marked as unavailable, then check to make sure your thermostat entity is climate.home. If it’s something else, like climate.my_ecobee, then update the templates above.

Calculating runtimes

Next, it’s time to use those templates to actually track the runtime. Home Assistants history stats integration is perfect for this.

These entities will start counting up whenever the fan state or run state is in the defined mode.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
sensor:
  - platform: history_stats
    name: HVAC Runtime Today
    entity_id: binary_sensor.hvac_fan_state
    state: 'on'
    type: time
    start: '{{ today_at() }}'
    end: '{{ now() }}'
  - platform: history_stats
    name: HVAC Runtime Cooling Today
    entity_id: binary_sensor.hvac_run_state
    state: 'cooling'
    type: time
    start: '{{ today_at() }}'
    end: '{{ now() }}'
  - platform: history_stats
    name: HVAC Runtime Heating Today
    entity_id: binary_sensor.hvac_run_state
    state: 'heating'
    type: time
    start: '{{ today_at() }}'
    end: '{{ now() }}'

Filter Change Tracking

The sensor.hvac_runtime_today resets every day, so if we want to track total runtime since a filter was replaced weeks or months ago, we need to keep summing it up.. The utility meter integration can do exactly that. I also store the filter change time just to make it easier.

In /config/configuration.yaml, create the following entities and reload.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
input_datetime:
  # Tracks when the filter was replaced
  hvac_filter_change_date:
    name: HVAC Filter Change Date
    has_date: true
    has_time: true

utility_meter:
  energy:
    name: HVAC Runtime Since Filter Change
    unique_id: SmRwiJmHh4FdbVftTDPD
    source: sensor.hvac_runtime_today

Dashboarding

Now, I’ve got a few different entities, here’s some sample dashboards. If you don’t already have it, I use the template-entity-row dashboard card row to help with some more complicated dashboards.

And the YAML:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
type: entities
entities:
  - entity: binary_sensor.hvac_fan_state
  - entity: sensor.hvac_run_state
  - entity: sensor.hvac_runtime_since_filter_change
  - entity: sensor.hvac_runtime_today
  - entity: sensor.hvac_cooling_runtime_today
  - entity: input_datetime.hvac_filter_change_date
    type: custom:template-entity-row
    name: Filter last changed
    state: >
      {{ time_since(states('input_datetime.hvac_filter_change_date') |
      as_datetime) }} ago
title: HVAC

Entity Reference

Let’s recap the entities we have created.

  • input_datetime.hvac_filter_change_date - Tracks the last time the filter has been changed
  • sensor.hvac_runtime_since_filter_change - Tracks how many minutes the unit has operated since changing the filter
  • binary_sensor.hvac_fan_state - Tracks whether the fan is running
  • sensor.hvac_run_state - Tracks what the thermostat is calling for (heating, cooling, fan, etc.)
  • sensor.hvac_runtime_today - Tracks how much the unit has run today
  • sensor.hvac_cooling_runtime_today - Tracks how much cooling the unit has done today
  • sensor.hvac_heating_runtime_today - Tracks how much heating the unit has done today

Sensing Temperatures

In this post, I showed some basic dashboarding for a thermostat in Home Assistant and also showed some advanced monitoring that used Home Assistant to track running times and temperatures for your HVAC unit which gives useful insights for maintenance and efficiency. The new metrics are easy to create and add to dashboards.

Going a step further, I created my own embedded device to measure air temperatures. Next up, I wanted to add some extra sensors to my HVAC unit itself. My system is self-contained inside my condo and I have access to the different pipes and vents, but a split unit installed outside may not be as accessible.

To handle this, I built my own prototype circuit. I started with an ESP32 running ESPHome. You can use any type of ESP32, but I had a few of the Adafruit Qt Py ESP32s lying around. ESPHome is a firmware development system that abstracts out writing C++ and you define sensors in YAML.

For my sensors, I opted for these thermocouples because they’re easy connect to the board and place them in specific areas. Thermocouples work by measuring change in resistance as the temperature changes. They don’t have any electronics themselves and require a separate component, an amplifier to convert that into something that the ESP32 can read.

Adafruit sells several different types of amplifiers including the MCP9600, MCP9601, MAX31856, and the MAX31850K, and a few others.

The MCP9601 is nice because it comes with a stemma connector, which is an Adafruit standard connector that allows for you to connect i2c devices without soldering, but the issue with i2c is that the address is hard-coded to a single address. Multiple amplifiers will conflict unless you change the address by adding a small amount of solder to the address change pads below.

The MAX variants are less accurate (0.25°C resolution) compared to the MCP960x at 0.0625°C resolution.

My first revision opted for the MCP9600 and I soldered the pins to the circuit and put them into a breadboard.

One thermocouple was inserted as close as possible to the supply duct that supplies the rest of the condo with heated or cooled air. The 5 meter thermocouple makes it easy to run the temp sensor right into it. The thermocouple wire can be seen in the picture below along the right side of the unit.

I also secured one to the water loop supplying hot and chilled water to my unit. During heating modes, it allows me to see how much heat I could put into the air. During cooling modes, the hotter it is, the harder my unit will work to put heat into it. This also gives me some data I can use to work with my building’s engineer to optimize the systme.

ESPHome Config

Here’s the configuration I used. If you use a different ESP32 board, some of this configuration will differ.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
esphome:
  name: qt-py-hvac-sensor
  platformio_options:
    board_build.f_cpu: 160000000L # 160MHz
    board_build.f_flash: 40000000L
    board_build.flash_mode: dio
    board_build.flash_size: 4MB


esp32:
  board: adafruit_qtpy_esp32
  variant: ESP32
  framework:
    type: arduino
    version: 2.0.6

wifi:
  ssid: !secret wifi_ssid
  power_save_mode: none
  password: !secret wifi_password
    
substitutions:
  device: "Qt Py Heat Pump"

mqtt:
  broker: mqtt.home.ajacqu.es
  discovery_unique_id_generator: mac
  discovery_object_id_generator: device_name

ota:
  - platform: esphome
    password: "..." #changeme

i2c:
  - id: stemma
    sda: SDA1
    scl: SCL1
    scan: true
    frequency: 10kHz

sensor:
  - platform: mcp9600
    id: temp
    hot_junction:
      name: "Loop Water Temperature"
      retain: false
    thermocouple_type: K
    address: 0x67
    update_interval: 60s

  # On a 5 meter cable to the output manifold
  - platform: mcp9600
    id: temp2
    hot_junction:
      name: "Air Supply Temperature"
      retain: false
    thermocouple_type: K
    address: 0x60
    update_interval: 60s

Future Work

In my next iteration, I plan to integrate a 24v DC regulator to pull power directly from the HVAC unit instead of having to run an ugly DC wire to a nearby closet. I want to add a few more thermocouple amplifiers to measure other areas, or even measure the pressure drop across the fan like this project, esphome-pressure demonstrates. I also want to make it a custom PCB so the board is a lot cleaner.

Conclusion

In this post, I showed some basic dashboarding for a thermostat in Home Assistant and also showed some advanced monitoring that used Home Assistant to track running times and temperatures for your HVAC unit which gives useful insights for maintenance and efficiency. The new metrics are easy to create and add to dashboards.

Going a step further, I created my own embedded device to measure air temperatures.

Copyright - All Rights Reserved

Comments

To give feedback, send an email to adam [at] this website url.

Donate

If you've found these posts helpful and would like to support this work directly, your contribution would be appreciated and enable me to dedicate more time to creating future posts. Thank you for joining me!

Donate to my blog