A Smart Home Heating Project with Promising Energy Saving Results

Introduction

With the recent energy price increases across the world it seemed like an appropriate time to post details of my project that attempts to save energy in the home by turning down the heating based on room occupancy.

I started automating my home heating system around 2 years ago and have been tweaking & improving it ever since. I made a number of changes over last summer with a view to using multiple sensors to help save energy and I am now in a position to compare how my energy usage has changed between the winter just gone and the previous winter (details are provided at the end of this post however if you don’t want to scroll down then the result is that savings of around 26% were achieved).

I should add that my heating system is all electric however most of my implementation could easily be replicated in other systems such as those which use automated TRV’s.

Heating System Overview

My heating system utilises Delonghi Fivvy oil filled electric panel radiators which utilise a fourth pilot wire signal to allow a central controller to set the rooms mode based on a timer that supports up to 4 independent zones. The desired room temperature is set on the radiators directly using a remote control and the central controller changes the mode (Comfort/Comfort-1C/Comfort-2C/Eco etc.) based on the program.

In order to replace the original controller and interface the system to Home Assistant I used several Qubino Z-Wave Flush Pilot Wire Modules (model number ZMNHJD1 for the EU). The number of modules required depends on the degree of control that is required, in my current setup I currently have 4 modules installed and each controls one or more radiators as follows:

  • Zone 1 - 4 x radiators in the hall and other bedrooms.
  • Zone 2 - 3 x radiators in the lounge/dining room.
  • Zone 3 - 1 x radiator in the study (home office).
  • Zone 4 - 1 x radiator in the master bedroom.

The bathrooms have wall mounted heaters that are controlled independently using Shelly 1’s and a traditional Thermostat in Home Assistant.

image

The above Qubino modules essentially operate as a dimmable light and the heater mode can be changed by setting the brightness level between 0 – 100%. In response, a variable 230VAC signal is sent on the pilot wire output that controls the radiator mode. The module also supports an external temperature sensor and 3 configurable switch inputs which I am not using. I currently use Aqara Zigbee temperature sensors in my setup as this was easier than installing hardwired temperature sensors in suitable locations away from the radiators.

Methods used to save Energy

I have used a number of different methods to try and reduce my overall energy consumption and these are summarised below:

  • Change all radiator modes to Eco when the home is detected as unoccupied.
  • Change a single radiators mode to Eco when the room is detected as unoccupied for greater than 30 minutes (primarily uses Z-Wave PIR sensors but also other sensors such as TV’s).
  • Change a single radiators mode to Eco when certain inhibit conditions for the room are detected e.g. open balcony door, open window, cooling fan running.
  • Dynamically adjust a radiators on time based on the rooms current temperature and it’s typical heat-up rate (oC/hr). This has the effect of bringing on the heating earlier if it is especially cold but also delays the heating coming on if the room is already warm e.g. due to the winter sun).
  • Use a modified Workday Binary Sensor to better suit our needs (essentially we stay up later on a Friday and go to bed earlier on a Sunday due to work so a traditional Monday to Friday workday sensor does not always work for us).

User Interface

There are two timers defined, one for Sleeping Areas and another for Living Areas. Each timer has a number of input_datetime entities which are used to define the on/off times for workdays and non-workdays respectively. In the case of the on times, these reflect the time the user wants the room up to temperature, the actual on time is determined by subtracting the calculated heat-up time as described above.

image

Each radiator (or group of radiators) has its own thermostat which uses the HACS Simple Thermostat custom card by @nervetattoo.

image

image

Features of the above card include:

  • Manual Mode toggle that allows the user to disable the timer function and manually select the preset using the buttons along the bottom of the card.
  • Inhibit Indication - if the heating is inhibited (forced to the Eco Preset) then the cause is shown via an orange icon.
  • Boost function that sets the Preset to Comfort for 1 hour and then reverts to the previous setting.
  • Advance feature that advances to the next timer setting (useful if the heating in on and you know you are going out shortly).
  • On at Night which sets the Preset to Eco during the night rather than Away.

Configuration

Most of the configuration is “home grown” yaml however I am making use of the HACS Home Assistant Qubino Wire Integration by @piitaya which is a customised thermostat specifically designed to work with the Qubino modules. Essentially it makes the relevant preset modes available on the thermostat card and allows you to control the modes without having to worry about hard-coding the relevant brightness levels for each of these.

I have included the yaml for the major parts on the configuration and hope to upload a more comprehensive version to Github once I have tidied things up a bit.

Customised Workday Binary Sensor:

    workday_heating:
      friendly_name: "Workday Heating"
      value_template: >
        {% set today = ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'][now().weekday()] %}
        {% set hour = now().hour %}
        {% if is_state('binary_sensor.workday', 'on') %}
          {{ 'false' if (today == 'Friday') and (hour > 12) else 'true' }}
        {% elif is_state('binary_sensor.workday', 'off') %}
          {{ 'true' if (today == 'Sunday') and (hour > 12) else 'false' }}
        {% endif %}

Example Zone Occupancy Binary Sensor:

    z4_occupied:
      friendly_name: "Z4 Occupied"
      device_class: occupancy
      value_template: >-
        {{is_state('binary_sensor.neo2', 'on') or
          is_state('binary_sensor.neo3', 'on') or
          is_state('binary_sensor.neo4', 'on') }}
      delay_on: "00:00:01"
      delay_off: "00:30:00"

Example Zone Inhibit Binary Sensor:

    z4_inhibit:
      friendly_name: "Z4 Inhibit Active"
      value_template: >-
        {{ is_state('switch.gosund02', 'on') or is_state('input_boolean.z4_manual_operation', 'on') or 
           is_state('binary_sensor.home_occupied', 'off') or is_state('binary_sensor.ensuite_window', 'on') }}

Example Zone Timer State Binary Sensor:

    z4_timer:
      friendly_name: "Zone 4 Timer"
      # Calc heat-up time and limit between 15 mins to 2.0 hrs
      value_template: >
        {% set time = (now().hour * 3600) + (now().minute * 60) %}
        {% set heatup_time = ((20.0 - states('sensor.bed1_temperature') | float(15)) / 1.5 * 3600.0 ) | int %}
        {% set heatup_time = [[heatup_time , 900] | max, 7200] | min %}
        {% if is_state('binary_sensor.workday_heating', 'on') %} 
           {% set on1  = state_attr('input_datetime.z1_on_time_am', 'timestamp') - heatup_time %}
           {% set off1 = state_attr('input_datetime.z1_off_time_am', 'timestamp') %}
           {% set on2  = state_attr('input_datetime.z1_on_time_pm', 'timestamp') - heatup_time %}
           {% set off2 = state_attr('input_datetime.z1_off_time_pm', 'timestamp') %}
        {% else %}
           {% set on1  = state_attr('input_datetime.z1_on_time_am_nwd', 'timestamp') - heatup_time %}
           {% set off1 = state_attr('input_datetime.z1_off_time_am_nwd', 'timestamp') %}
           {% set on2  = state_attr('input_datetime.z1_on_time_pm_nwd', 'timestamp') - heatup_time %}
           {% set off2 = state_attr('input_datetime.z1_off_time_pm_nwd', 'timestamp') %}
        {% endif %}
        {% if ((time >= on1) and (time < off1)) or ((time >= on2) and (time < off2)) %} true
        {% else %} false
        {% endif %}

Example Zone Preset Actual Sensor (used for testing and will eventually be removed):

    z4_preset_act:
      friendly_name: Zone 4 Preset Act
      value_template: >-
        {% set mapper =
          { '0':'Unknown', '10':'Standby', '20':'Away', '30':'Eco', '40':'Comfort -2C', '50':'Comfort -1C', '100':'Comfort' } %}
        {% set state =  (state_attr('light.qubino_pw04_level','brightness') | int * 100 / 255) | int | string %}
        {{ mapper[state] if state in mapper else 'Unknown' }}

Example Zone Heat-up time Sensor:

    z1_heatup_time:
      friendly_name: "Zone 1 Heatup Time"
      unit_of_measurement: min
      value_template: >
        {{ [((21.0 - states('sensor.bed1_temperature') | float(19.5) | float) / 1.5 * 60.0 ) | int, 900] | min }}

The main Heating Control Automation Blueprint:

blueprint:
  name: Heating Control
  description: Controls heating for a given zone thermostat
  domain: automation
  input:
    advance:
      name: Advance
      description: The entity that activates the heating advance function for the zone.
      selector:
        entity:
          domain: input_boolean
    boost:
      name: Boost
      description: The entity that activates the heating boost function for the zone.
      selector:
        entity:
          domain: switch
    inhibit:
      name: Inhibit
      description: The entity that indicatess when the heating for the zone is inhibited (e.g. due to an open window).
      selector:
        entity:
          domain: binary_sensor
    manual_operation:
      name: Manual Operation
      description: The entity that activates manual operation or the zone (the automatic timer and advance/boost functions are disabled when Manual Operation is on).
      selector:
        entity:
          domain: input_boolean
    night:
      name: Night
      description: The entity that activates the night function for the zone (selects heating on with the Eco Preset during the night).
      selector:
        entity:
          domain: input_boolean
    preset_act:
      name: Preset Actual
      description: The entity that displays the current preset for the zone.
      selector:
        entity:
          domain: sensor
    qubino:
      name: Qubino
      description: The enitity that controls the Qubino Pilot Wire Module for the zone.
      selector:
        entity:
          domain: light
    thermostat:
      name: Thermostat
      description: The entity that acts as the user interface for the zone in the Front End.
      selector:
        entity:
          domain: climate
    timer:
      name: Timer
      description: The entity that indicates when the zones automatic timer is in the on state.
      selector:
        entity:
          domain: binary_sensor
    warm_up_timer:
      name: Warm-up Timer
      description: The entity that keeps the heating on for a pre-defined period after the heating turns on.
      selector:
        entity:
          domain: timer
    warm_up_duration:
      name: Warm-up Duration
      description: Duration for the Warm-up Timer.
      selector:
        time:
mode: restart
max: 10
variables:
  boost_entity: !input boost
  night_entity: !input night
  inhibit_entity: !input inhibit
  qubino_entity: !input qubino
  timer_entity: !input timer
  warm_up_timer_entity: !input warm_up_timer
  advance_entity: !input advance

trigger:
  - entity_id: !input inhibit
    platform: state
  - entity_id: !input night
    platform: state
  - entity_id: !input advance
    platform: state
    to: "off"
  - entity_id: !input advance
    id: advance_on
    platform: state
    to: "on"
  - entity_id: !input boost
    platform: state
    to: "off"
  - entity_id: !input manual_operation
    platform: state
    to: "off"
  - entity_id: !input timer
    id: timer_off
    platform: state
    to: "off"
  - entity_id: !input timer
    id: timer_on
    platform: state
    to: "on"
  - entity_id: !input boost
    id: boost_on
    platform: state
    to: "on"
  - entity_id: input_boolean.heating_start
    id: heating_start_on
    platform: state
    to: "on"
  - entity_id: !input manual_operation
    id: manual_on
    platform: state
    to: "on"
  - entity_id: !input warm_up_timer
    platform: state
    to: idle
condition: []
# Perform admin tasks prior to setting heating for this zone
action:
  - choose:
      - conditions:
          - condition: trigger
            id: advance_on
        sequence:
          - service: switch.turn_off
            target:
              entity_id: !input boost
      - conditions:
          - condition: trigger
            id: boost_on
        sequence:
          - service: input_boolean.turn_off
            target:
              entity_id: !input advance
      - conditions:
          - condition: trigger
            id: manual_on
        sequence:
          - service: homeassistant.turn_off
            target:
              entity_id:
                - !input advance
                - !input boost
                - !input thermostat
      - conditions:
          - condition: trigger
            id: timer_off
        sequence:
          - service: input_boolean.turn_off
            target:
              entity_id: !input advance
      - conditions:
          - condition: trigger
            id: timer_on
        sequence:
          - service: input_boolean.turn_off
            target:
              entity_id: !input advance
          - service: timer.start
            data:
              duration: !input warm_up_duration
            target:
              entity_id: !input warm_up_timer
    default: []
  # Only continue if heating_start flag is on and this zone is not in manual
  - condition: and
    conditions:
      - condition: state
        entity_id: input_boolean.heating_start
        state: "on"
      - condition: state
        entity_id: !input manual_operation
        state: "off"
  # Small delay to allow admin tasks to fully complete
  - delay: 00:00:01
  # Set heating for this zone
  - service: homeassistant.turn_on
    data_template:
      brightness_pct: >
        {% if    is_state(boost_entity, 'on') %} 100
        {% elif  is_state(timer_entity, 'on')  and is_state(advance_entity, 'on')  %}  10 
        {% elif (is_state(timer_entity, 'on')  or  is_state(advance_entity, 'on')) and is_state(warm_up_timer_entity, 'active')  %} 100
        {% elif (is_state(timer_entity, 'on')  or  is_state(advance_entity, 'on')) and is_state(inhibit_entity, 'off') %} 50
        {% elif  is_state(timer_entity, 'on')  and is_state(inhibit_entity, 'on') %} 30
        {% elif  is_state(timer_entity, 'off') and is_state(night_entity, 'on') and   is_state('binary_sensor.night_time', 'on') %} 30
        {% elif  is_state(timer_entity, 'off') %} 10
        {% else %} 0
        {% endif %}
      entity_id: "{{ qubino_entity }}"
  - delay: 00:00:01
  - service: homeassistant.update_entity
    data: {}
    entity_id: !input preset_act

In addition to the above there are a number of helpers for each zone which I have configured via the UI:

  • Zone 4 Advance (Toggle)
  • Zone 4 Manual Operation (Toggle)
  • Zone 4 on at Night (Toggle)
  • Zone 4 Warm Up Timer (Timer)

Possible Improvements

  • Add additonal Qubino modules to provide more granular control of rooms.
  • Use the Proximity Integration to detect when we are approaching home to turn on the heating (currently this relys on prescence detection so there can be a delay before the home heats up).
  • Use bed occupied detection to determine when everyone has gone to bed (this would avoid the 30 minute occupancy delay before radiators turn off).
  • Rewrite the Blueprint to set preset modes by name rather than by dimmer percentage (this would improve readability of the code).

Results

Firstly congratulations if you made if this far!

The table below shows the difference in our energy consumption over the past two winters i.e. before and after implementing the automations described above. This shows a consistent monthly reduction totalling 2836KWh which equates to a saving of ÂŁ414 ($541) at our current unit rate of 14.6p/kWh. Note that this will have a much larger effect when our current fixed rate deal ends in July and the unit rate is expected to more than double!

image

I do accept that there may be other factors at play such as how cold a winter is etc, however I am pleased with the results so far and will continue to monitor this going forward and aim to implement additional improvements.

Please note that this is very much a work in progress but I hope that it might give ideas or inspiration to others and welcome any comments or suggestions.

5 Likes

I’m also looking to solutions to save money on heating bills. But first one have to understand how house or building are made and how they retain heat. In Europe houses are usually build of bricks and reinforcement cement with insulation from out side. Bricks and reinforcement cement are materials that have high thermal capacity. Thermal capacity is ability of material to store heat or cold and than release it in room. When I heat my house in the winter majority of hot air is used to heat house walls and floor. Those materials retain heat and later release it in the inner space of the house. In my experience that means that you have to heat house with enough energy to keep walls and floors warm enough. If you dont do that walls and floors will cool down and house will act like a big fridge. It will take a few weeks and lot of heating to heat a house.
I have buderus logamatic 2107 gas furnace. Its a bit old but highly reliable product from buderus. I managed to fine tuning it with room temperature sensors that I installed around house to monitor room temperature and heat loses. i also have a buderus hot water tank which use a lot of gas, especially in winter. Around 20 - 30 % of gas bill is spent on inefficient hot water tank.
I also realized this winter that some parts of the house is warmer and some are colder than average house temperature. This is happening because some rooms are facing south and sun, even in winter, can heat up during the day rooms on 20 - 21 C even with radiators shut down.
My next project is installing smart thermostatic radiator valves to control house heating on the fly per radiator. As my furnace is not smart it is heating the whole system with some amount of energy. But if you shut down one, two, or more radiators because its too hot in the room, it will send more heat to the radiators in colder rooms or colder part of the house that are open.
By fine tuning heating system it is possible to gain some saving but people shouldn’t expect miracles. Savings up to 30 % is possible but that is upper limit at least in my experience.

1 Like

This is awesome, I’m doing a similar project with my oil furnace and hot water heat. I need to dig into what you did a bit more.

This is a pretty cool idea, but like the post above, I would add that it depends highly on the type of building and heating.

We have a well insulated house and floor heating. Currently driven by a Vaillant Gas furnace but soon we will get a heat pump.

Insulation, Heat Pump and floor heating all mean the system is pretty slow and stable, so working with room occupancy is out of the question.
What I would really love is a system that takes the weather report into consideration. Our heating has a sensor outdoors that measures the current temperature and sets the heater accordingly, but this does more harm than good because it doesn’t take into account how warm the rooms already are and also doesn’t know how warm or cold it will be in the next days.

A smart, maybe even AI driven system that checks the weather report, makes decisions based on current and future/predicted conditions and combines as many sources as possible (like using solar power when available etc) would probably yield the best results, but is unfortunately far too complex for me to even attempt.

I was making inquiries about heat pump system. It does look great on paper but in real life I’m not that sure. This system is made to mainly work with floor heating as it needs less energy. But there is also a draw back. As I know you can’t switch floor heating off. It takes days for floor heating to heat a house once it was turned off.
You can use heat pumps to heat radiators but price for that is absurd.
It is possible to make house heating in the way that every room has it’s on thermostat and that furnace can individually heat one room or even one radiator. But this is very expensive.
In my opinion the best was to simulate this is using smart trv.
My buderus gas furnace has outdoor temperature sensor. But its mounted on the side of the house that is never hit by a sun. Today on sunny side of the house was 24 degrees. Sensor is in the shade but on sunny side.
Room temperature rised to 22 without heating.
I’m waiting this winter to saw how exactly this setup will work.

1 Like

We currently have all the hardware…room thermostats (smarthome), floor heating, heat pump (soon) and solar (soon) so all I really need is the software…but it’s a nice to have, not a need to have…:innocent:

well good luck. I hope your heat pump will work. As I know it will but overall cost of running it might be much higher than expected because people doesnt usually count on regular maintenance, I heard that maintenance cost are high.

Maintenance cost is less than for a gas heater. The risks are mostly bad planning (too large heat pump will not run efficiently and break more quickly) and placement (wind direction). Wind direction is a concern for us, but shielding the heat pump from direct headwind is manageable.

I was planing to install water tank with integrated heat pump as a replacement for my water tank that use gas. But the guy who does installation for heat pumps said in friendly conversation not to do it.
He told me that head pumps does work but it requires some other things like very thick insulation, triple glazing, very clean environment. He pointed out that maintenance of those device will be high and in the end I will spend the same amount of money every year.
I don’t have any experience with heat pumps and know about it what I have been told.
Maintenance of my old buderus is every two to three years, just to clean it. I didn’t done any maintenance on it for ten years and it never broke down. Running 24/7 365 days,

Since we already have triple glazing and everything it’s fine for us. Maintenance for our gas heater is every year, will he the same for the heat pump but cheaper since it’s less work.

1 Like

Don’t get me wrong I’m just sharing my thoughts with you in a conversation.

No worries, all fine by me… :wink:

Now back to Topic:

I just thought about possible smart heating schemes, and cam up with the following theory:

Most heating systems are based on outdoor temperature. So if it’s cold they will turn up the “Vorlauftemperatur” to compensate. They are usually based on the current outdoor conditions though, and with a we insulated house and a slow heating system like floor heating they don’t always work perfectly.
So…how about working with a temperature delta, based on the forecast? Essentially, look at the temperature and sunshine predictions 2-3 days in the future. If the temperature delta between inside and outside is going to be smaller in 2 days than it is now, then turn down the heating by 2°C for all thermostats (or the heater directly if you can control it) because the sunand warmth will heat your house back up for free then when it turns warmer.
If the delta in 2 (or 3) days is bigger than it is now, do the opposite…turn the temp up by 2°C since it is fairly cheap to heat a house to 22°C if it’s 18°C outside…and then you “bunker” the cheap heat for the colder days where it would then be set back to your baseline (for us that’s 20 in the living room and bathroom and 18 in the bedroom and some of the other rooms.

This would need quite a few conditions so that it doesn’t cause unwanted side effects, but might be worth considering? Or am I on a wild goose chase here?

Edit: I just found “Better Thermostat” for Home Assistant and will check it out…looks interesting.

This is awesome

What would you use to design a Zigbee - heck even a Thread - alternative?

Hi, I used the Qubino ZMNHJD1 modules which are Zwave because they were the only ones I could find that supported the pilot wire heating standard at the time.

I am not aware of many Zibgee solutions for pilot wire radiators although I did find the following link which may be of interest:

The other option is to look at WiFi radiators, there are quite a few of these systems available depending on your country but then the problem may be interfacing these with Home Assistant (Zigbee and Zwave make this much easier).

I think it is too early to consider thread as the products need to be developed first.

Hi @Jonah1970

Would you mind sharing your card config for simple-thermostat - I’ve managed to get so far but can’t quite match up with your design which I’d like to use as the basis for my zigbee-based heating solution.

I got a bit closer but still can’t get the state buttons to show (the standby and heat buttons in your example).

Sure, here you go …

cards:
  - type: glance
    title: Zone 2 - Living Areas
    entities:
      - entity: schedule.z2_workdays
        name: WD Sched
      - entity: schedule.z2_non_workdays
        name: NWD Sched
      - entity: binary_sensor.z2_timer
        name: Timer
      - entity: timer.z2_warm_up
        name: Warm-up
  - type: custom:simple-thermostat
    entity: climate.study_thermostat
    hide:
      state: true
    setpoints:
      temperature:
        hide: true
    sensors:
      - entity: switch.z3_boost
      - entity: input_boolean.z3_advance
      - entity: input_boolean.z3_night
      - entity: sensor.z3_preset_act
    header:
      name: Study
      icon: 'false'
      faults:
        - entity: binary_sensor.z3_fault
          icon: mdi:alert
        - entity: binary_sensor.z3_zwave
          icon: mdi:z-wave
        - entity: binary_sensor.z3_inhibit
        - entity: input_boolean.z3_manual_operation
        - entity: binary_sensor.z3_unoccupied
          icon: mdi:motion-sensor-off
      toggle:
        entity: input_boolean.z3_manual_operation
        name: Man
    control:
      hvac:
        _name: State
        'off':
          name: Standby
        heat:
          icon: mdi:radiator
      preset:
        _name: Mode
        away:
          icon: mdi:snowflake
        eco:
          icon: mdi:leaf
        comfort-2:
          icon: mdi:radiator
          name: Comfort-2
        comfort-1:
          icon: mdi:radiator
          name: Comfort-1
        comfort:
          icon: mdi:radiator
    card_mod:
      type: custom:simple-thermostat
      style: |
        ha-card {
          --st-font-size-xl: 24px;
          --st-font-size-m: 20px;
          --st-font-size-title: 20px;
          --st-font-size-sensors: 15px;
          --st-spacing: 3px;
        }
type: vertical-stack
1 Like

It’s not super complicated though it requires a set of calculations and operation modes,

For each zone:

  • schedule temperature - the temperature for the zone
  • weather cut - a calculation that cuts temperature based on weather, sun. 0-2 degrees
  • boost - a calculation that may boost this zones temperature by 1 degree when other zones are in demand, to reduce and align furnace firing

These 3 add together to make the target temperature. An automation picks this up and sends it to the climate entity for the zone.

The schedule temperature gets set by automations to run the heating schedule, morning wake-up, nighttime cooldown, etc.

In additions I have 3 operation modes:

  • normal - aka following the schedule
  • override - temporary overrides, primarily I use this since I have a Woodstove, when the stove heats up, the zones are set into override, since the stove will start creating heat
  • away - what happens when I’m away for more than a day.

Cheers - I got 99% of the way until I realised some of the missing entities are down to my devices - I have some Zigbee (Moes) TRV’s and they only provide “HEAT” on the hvac_mode attribute which is what was confusing me. Really odd that the TRV doesn’t have an “OFF” mode and I’m yet to find a way to simulate it with a template/dummy device which sets the setpoint to 5 degrees if the mode is set to “OFF”.

Great, glad you got things sorted!