Solar-powered smart convector heater

In this article I want to share how I’ve been using a 2kW convector heater with excess solar power.

The main rationale behind this was the fact I still hadn’t had my solar export tariff (and payments) in place, meaning I either use all the solar power or simply export it and don’t get a penny.

How does it work? The idea is pretty simple, if there is more than ~2500W of power available (either being fed back to the grid or charging the battery) then put the heater on. Switching on/off is done via a smart socket (rated to 13A). And because I already had the heater (from over 10 years ago) and a spare smart socket (used for be for Christmas lights), the hardware cost was £0.

In case you are getting paid for exporting your surplus solar energy, this automation will still make financial saving if the export per kWh is lower than your heating cost per kWh. For example, if you can get 5p per exprted kWh and pay 10p per kWh of gas, running this setup up will save you over 5p per kWh for heating your space. And at much lower carbon footprint!

The simple dashboard I’ve put together for this looks like this:
Screenshot at 2023-02-22 21-58-41

and this is what it looks like in action (top - whether heater should be turned on (Request 2kW Heater) and whether it is turned on (Heater); middle - solar, battery and grid power; bottom - battery charge level in %):

Automation

Below are code snippets you can adopt to your needs - for all my setup please see my github repo.

I’ve decided to split the calculation of the on/off state from the actual turning on/off. The main reason was to get better visibility of the calculations and to keep the automation logic itself quite simple.

The on/off state is calculated as a binary_sensor template called Request 2kW Heater. This checks various energy status to determine if the heater should be on or off. Anything that resolves to true means heater should be on. In addition, the logic to determine if the heater should be on, takes into account the following:

  • try to prioritise battery charging
  • inverter can only output 5.5kW, so existing load (before switching it on) needs to be below 3.5kW
  • there needs to be enough spare power to cover the heater and a bit of battery charging
  • required solar output decreases as the battery gets fuller to try to avoid it hitting 100%
  # Logic divided into base conditions (bc) that apply regardless, and battery/solar specific
  - binary_sensor:
    - name: "Request 2kW Heater"
      state: >
        {% set alreadyOn = is_state('switch.heater', 'on') %}
        {% set batteryCharging = states('sensor.solax_local_battery_power_adjusted')|int %}
        {% set pv = states('sensor.solax_local_pv_output')|int %}
        {% set feedIn = states('sensor.solax_local_feedin_power')|int %}
        {% set load = states('sensor.solax_local_load_power')|int %}
        {% set batteryLevel = states('sensor.solax_local_battery_soc')|int %}
        {% set sparePower = feedIn + batteryCharging %}
        {% set bc = (feedIn > -100) and ((alreadyOn==false and load < 3500) or (alreadyOn==true and load < 5500)) %}
        {{ bc and ((pv > 3000 and alreadyOn==false and sparePower > 3000 ) 
                or (pv > 3000 and alreadyOn==true  and sparePower >  800 ) 
                or (pv > 2600 and alreadyOn==false and sparePower > 2600 and batteryLevel >  85 ) 
                or (pv > 2600 and alreadyOn==true  and sparePower >  400 and batteryLevel >= 85 ) 
                or (pv > 2200 and alreadyOn==false and sparePower > 2200 and batteryLevel >  90 ) 
                or (pv > 2200 and alreadyOn==true  and sparePower >  100 and batteryLevel >= 90 ) 
                or (pv >  300 and alreadyOn==false and sparePower >  300 and batteryLevel >  93 ) 
                or (pv >  300 and alreadyOn==true                        and batteryLevel >= 93 )) }}

And two simple automations to turn the heater on/off based on the value of the binary_sensor.request_2kw_heater. Both with a 15-second check to avoid flicking between on/off states, and so that once on, it says for on for at least 15 seconds.

- id: '1672233470659'
  alias: Sinks - Heating - Start electric heater (excess solar)
  description: ''
  trigger:
  - platform: state
    entity_id: binary_sensor.request_2kw_heater
    for:
      hours: 0
      minutes: 0
      seconds: 15
    to: "on"
  action:
  - type: turn_on
    device_id: 273edc8e0b6dcd4117de51becf83b2d0
    entity_id: switch.heater
    domain: switch
  mode: single

- id: '1634984084830'
  alias: Sinks - Heating - Stop electric heater
  description: ''
  trigger:
  - platform: state
    entity_id: binary_sensor.request_2kw_heater
    for:
      hours: 0
      minutes: 0
      seconds: 15
    to: "off"
  action:
  - type: turn_off
    device_id: 273edc8e0b6dcd4117de51becf83b2d0
    entity_id: switch.heater
    domain: switch
  mode: single

In addition to the automations, I’m also using powercalc to measure that ammount of energy used, which can be reported in the Energy dashboard or custom tile:

### Fixed-load Sinks ###
- platform: powercalc
  entity_id: switch.heater
  name: Electric Heater Aggregated
  fixed:
    power: 2000

utility_meter:
  daily_electric_heater:
    source: sensor.electric_heater_aggregated_energy
    name: Daily Electric Heater 
    cycle: daily

Summary

For all this to work, you also need real-time readings from your solar inverter and a CT clamp - for how I’ve done this see Solax X1 Hybrid G4 (local & cloud API). With a few modifications, this could easily work with any other source of real-time energy generation and usage info.

If you are interested in doing something similar with a hot water immersion heater, please see my Smart immersion heating for domestic hot water article.

Please comment if you have any suggestions for improvements or need any clarifications.

Happy heating! :slight_smile:

4 Likes