Heater coexistence on the same circuit

This is a relatively small one but works better than I expected. The basic idea is: I have two 1500W heaters in two separate rooms but on the same puny 15A circuit. If they’re both running at the same time, there’s about six seconds or so before the breaker cuts out. I could theoretically just set them both to “low”, but with the cold winter that just makes neither of them keep up.

The idea, then, is to use Hass-controlled plugs to coordinate them, so only one is running at a time. To make things easier (and nicer), both have their temperature dials set full-tilt and I use the generic thermostat to actually regulate temperatures. I opted for Aeotec Smart Switch 6 plugs for the power monitoring and encrypted communication, and Iris contact sensors for temperature sensing, because they’re cheap and I’ve had good results overall.

So, first of all, I have two input_booleans that represent whether that room wants heat:

input_boolean:
  ne_bedroom_request_heat:
    initial: 'off'
  nw_bedroom_request_heat:
    initial: 'off'

And then the virtual thermostats:

climate ne_bedroom:
  platform: generic_thermostat
  name: NE Bedroom
  heater: switch.ne_bedroom_request_heat
  target_sensor: sensor.centralite_3320l_0e261180_1
  target_temp: 60
  ac_mode: no
  min_temp: 35
  max_temp: 90

climate nw_bedroom:
  platform: generic_thermostat
  name: NW Bedroom
  heater: switch.nw_bedroom_request_heat
  target_sensor: sensor.centralite_3320l_0ded19ff_1
  target_temp: 60
  ac_mode: no
  min_temp: 35
  max_temp: 90

You might’ve noticed the heater entity_ids above. Well, I didn’t find out until today that generic_thermostat has been fixed to work with any boolean entity. I’ll play with that later, but for now here’s the old workaround:

switch:
  - platform: template
    switches:
      ne_bedroom_request_heat:
        value_template: "{{ is_state('input_boolean.ne_bedroom_request_heat', 'on') }}"
        turn_on:
          service: input_boolean.turn_on
          entity_id: input_boolean.ne_bedroom_request_heat
        turn_off:
          service: input_boolean.turn_off
          entity_id: input_boolean.ne_bedroom_request_heat
  - platform: template
    switches:
      nw_bedroom_request_heat:
        value_template: "{{ is_state('input_boolean.nw_bedroom_request_heat', 'on') }}"
        turn_on:
          service: input_boolean.turn_on
          entity_id: input_boolean.nw_bedroom_request_heat
        turn_off:
          service: input_boolean.turn_off
          entity_id: input_boolean.nw_bedroom_request_heat

So, that’s the virtual thermostats and the input_boolean flags they twiddle. Now how does this get tied to the actual switches? Through a series of automations, of course.

I wanted the NW bedroom to be “dominant” as I actually sleep in there. So it overrides the NE bedroom when needed.

First, a safety measure, so I’m hopefully not totally dependent on the circuit breaker defusing an unsafe situation:

automation heater_coex_safety:
  alias: Heater coexistence -- safety
  trigger:
  - platform: state
    entity_id: switch.ne_bedroom_heater_switch
  - platform: state
    entity_id: switch.nw_bedroom_heater_switch
  condition:
  - condition: state
    entity_id: switch.nw_bedroom_heater_switch
    state: 'on'
  - condition: state
    entity_id: switch.ne_bedroom_heater_switch
    state: 'on'
  action:
    service: switch.turn_off
    entity_id: switch.ne_bedroom_heater_switch

Yes, no from/to in the trigger. I wanted it as greedy as possible, so that the condition gets checked at any remote possibility they’ve both wound up on simultaneously.

Let’s turn some heaters on:

automation heater_coex_nw_on:
  alias: Heater coexistence -- NW on
  trigger:
  - platform: state
    entity_id: input_boolean.nw_bedroom_request_heat
    from: 'off'
    to: 'on'
    for:
      seconds: 5
  action:
    service: switch.turn_on
    entity_id: switch.nw_bedroom_heater_switch

Through the automations themselves, I’m building in a 5 second delay. Good to have that little buffer in case of lag on the Z-Wave network. Again, since NW preempts NE, it doesn’t check whether NE is running. Instead, NE checks if NW is running.

automation heater_coex_ne_on:
  alias: Heater coexistence -- NE on
  trigger:
  - platform: state
    entity_id: input_boolean.ne_bedroom_request_heat
    from: 'off'
    to: 'on'
    for:
      seconds: 5
  - platform: state
    entity_id: switch.nw_bedroom_heater_switch
    from: 'on'
    to: 'off'
    for:
      seconds: 5
  condition:
    - condition: state
      entity_id: input_boolean.ne_bedroom_request_heat
      state: 'on'
    - condition: state
      entity_id: input_boolean.nw_bedroom_request_heat
      state: 'off'
  action:
    service: switch.turn_on
    entity_id: switch.ne_bedroom_heater_switch

I decided it makes more sense to check if the NW bedroom wants heat when deciding whether to turn the NE heater on as opposed to checking the switch itself, since due to the 5 second delay, the NW bedroom heater may not have turned on just yet.

And turning heaters off:

automation heater_coex_nw_off:
  alias: Heater coexistence -- NW off
  trigger:
  - platform: state
    entity_id: input_boolean.nw_bedroom_request_heat
    from: 'on'
    to: 'off'
  action:
    service: switch.turn_off
    entity_id: switch.nw_bedroom_heater_switch

When you look at this automation you might think, why not connect the thermostat directly to the switch? Well, I want that 5 second delay when it comes on, but immediate when it turns off. This seemed like the most straightforward way to do it.

automation heater_coex_ne_off:
  alias: Heater coexistence -- NE off
  trigger:
  - platform: state
    entity_id: input_boolean.ne_bedroom_request_heat
    from: 'on'
    to: 'off'
  - platform: state
    entity_id: input_boolean.nw_bedroom_request_heat
    from: 'off'
    to: 'on'
  action:
    service: switch.turn_off
    entity_id: switch.ne_bedroom_heater_switch

Straightforward. NW heater coming on? Turn off. No longer need heat? Turn off.

So that’s pretty much it. Heaters turn on with a 5 second delay, turn off immediately. When both rooms want heat, the NW heater is on. When only the NW room wants heat, the NW heater is on. When only the NE room wants heat, the NE heater is on. When neither want heat, both are off. Breaker doesn’t pop, and the rooms stay warm.

I discovered an interesting race condition in this. If the NW heater turns off less than 5 seconds after the NE room requests heat, the NE heater won’t wait the full 5 second delay. I decided it’s too harmless to try to fix.

2 Likes

I have a recent similar situation and some automation was on my list. This should make it pretty easy now :slight_smile: Thanks!

Works great! Thanks again!