Atlantic Aurea hybrid heatpump controller

Herewith I share my implementation for the Atlantic Aurea hybride heatpump. Feedback and suggestions are welcome!

Atlantic Aurea is a hybride heatpump that switches between traditional gas a and heatpump heating. It comes with the Plugwise Smile Opentherm module and a Plugwise Anna thermostat. (see Aurea Hybride add-on - Atlantic Therefore, it can be integrated in Home Assistant using the Plugwise integration.

Unfortunately, there is no direct way to set it to gas or heatpump operation. I experimented with some parameters to influence this. I use an automation that manipulates the Anna thermostat between certain limits to ‘force’ the heatpump mode instead of gas where possible. As long as the outside temperature is higher than 4.5 degrees, it keeps the heatpump running when there is a heat request.

The Anna thermostat is only used to controll the Atlantic aurea, and is in my case located near the gas heater. Instead I use zwave radiator thermostats, so the user can set the temperature there, but couls also be done using a seperate wall thermostat that sets the input helper.

I use multiple temperature sensors in the house and an input_number helper that can be set to enter the desired temperature per room. finally I calculate the difference between de desired temperature and the measured average temperature. This is called the temperature_request.


front end for the users

Settings front end


Stuff for the nerd

Code below is my package (see Packages - Home Assistant) that defines both helpers and the automation.

it defines these entities:

entity description
input_number.heatpump_setpoint temperature that the controller wil set the Anna to in order to manipulate it
input_number.temperature_target desired home temperature
sensor.temperature_avg Average temperature for a room when multiple temperature sensors are used
sensor.temperature_req_generic ultimate heat request from all rooms
sensor.temperature_req calculated hear request (difference between measured and requested temperature)
sensor.heatpump_status indicator if the heatpump is in heatpump or hybrid mode
sensor.delta_water_heat actual amount of degrees the unit feeds into the house
sensor.delta_setpoint difference between actual Anna setpoint and anna temperature
sensor.heating_capacity Percesntage heating power used, for both gas or electric
sensor.heatpump_capacity percentage power used for heatpump only (based on electricity usage measurement)
binary_sensor.heatpump_active indicating if the heatpump is on

Note: the capacity of the heatpump is measured using a power plug meter the heatpump is connected to. (in my case sensor.heatpump_electric_consumption_w)

Additionally, it requires the following sensors:

sensor description
input_boolean.heatpump_force helper entity to enable or disabling the manipulation
sensor.smile_anna_outdoor_temperature provded by Plugwise Anna thermostat
sensor.opentherm_modulation_level provded through Plugwise Smile by you gas heater using OpenTherm
sensor.opentherm_water_temperature provded through Plugwise Smile by you gas heater using OpenTherm
sensor.opentherm_intended_boiler_temperature provded by Plugwise Smile
sensor.opentherm_return_temperature provded through Plugwise Smile by you gas heater using OpenTherm
binary_sensor.opentherm_tap_water provded through Plugwise Smile by you gas heater using OpenTherm
climate.anna provded by Plugwise Anna thermostat

The Package

heatpump_controler_automation:

# -- COMPONENTS --
# specific components are defined here

  input_number:
    heatpump_setpoint:
      name: doeltemperatuur warmtepomp
      icon: mdi:thermometer
      unit_of_measurement: '°C'
      min: -10
      max: 55
      mode: box

    temperature_target:
      name: Thermostaat doeltemperatuur
      min: 10
      max: 28
      step: 0.5
      mode: box
      unit_of_measurement: '°C'
      icon: mdi:home-thermometer-outline

  sensor:
  - unique_id: S9875243095876324
    name: temperature_avg
    platform: min_max
    type: median
    round_digits: 1
    entity_ids:
      - sensor.temperature_1 
      - sensor.temperature_2 
      - sensor.temperature_3 

  - unique_id: B003874B41197742D5AC2D1552F5630B0
    name: temperature_req_generic
    unit_of_measurement: '°C'
    platform: group
    type: max
    entities:
      - sensor.temperature_req
   #  - sensor.temperature_req_living
   #  - sensor.temperature_req_office


  template:
    - unique_id: C09323445876
      sensor:
      - name: "temperature_req"
        icon: mdi:thermometer-plus
        device_class: temperature
        unit_of_measurement: '°C'
        state: >
          {%- set raw_req=(states("input_number.temperature_target") | float(0) - states("sensor.temperature_avg") | float(0)) | round(1)-%}
          {%- if raw_req > 0 -%}{{raw_req}}{%- else -%}0{%- endif -%}


    - sensor:
        unique_id: 01618CE9-A658-4140-87C5-7B597B9BC13C
        name: heatpump_status
        icon: mdi:heat-pump-outline
        state: >
          {% set current = this.state |default("", 1)%}
          {% if trigger.platform == 'state' or trigger.event.data.value is not defined %}
            {{ current }}
          {% else %}
            {{ trigger.event.data.value }}
          {% endif %}    
      trigger:
        - platform: event
          event_type: heatpump_status_value

    - sensor:
        unique_id: c127cd2a-3112-b574-32ab-92c6dd8a322a
        name: delta_water_heat
        icon: mdi:thermometer
        unit_of_measurement: '°C'
        state: >
            {% set delta= (states("sensor.opentherm_water_temperature") | float(0) - states("sensor.opentherm_return_temperature") | float(0)) | round(2) %}
            {%- if delta > 0-%}
              {%- if delta < 30-%}{{ delta }}
              {%- else -%} 30 {%- endif -%}
            {%- else -%} 0 {%- endif -%}

    - sensor:
        unique_id: c234ab1b-3112-b574-32ab-92c6aaba88311b
        name: delta_setpoint
        icon: mdi:thermometer
        unit_of_measurement: '°C'
        state: >
          {{ (states("sensor.anna_setpoint") | float(0) - states("sensor.anna_temperature") | float(0)) | round(2) }}
      
    - sensor:
        unique_id: c321122a-127cd-b574-32ab-92c6dd8b113
        name: heating_capacity
        unit_of_measurement: '%'
        state: >
          {% if states("sensor.opentherm_modulation_level") | float(0) > 0 %}
            {{ states("sensor.opentherm_modulation_level") | float(0) }}
          {%- else -%}
            {% set cap = (((states('sensor.heatpump_electric_consumption_w') | float(0) - 12 ) / 2500 ) * 100) | float(0) | round(1) %}
            {% if cap < 0 -%}{% set cap = 0 %}{%- endif %}{{ cap | float(0) }}
          {%- endif %}  

    - sensor:
        unique_id: A321122a-127cd-b574-32ab-92c6dd8b111
        name: heatpump_capacity
        unit_of_measurement: '%'
        state: >
            {% set cap = ((states('sensor.heatpump_electric_consumption_w') | float(0) - 12 ) / 25) | float(0) | round(1) %}
            {% if cap < 0 -%}{% set cap = 0 %}{%- endif %}{{ cap | float(0) }}

    - binary_sensor:
        unique_id: bb2bcf8e-692b-4cbe-b1ee-7c60a87b212
        name: heatpump_active
        icon: mdi:heat-pump-outline
        state: >
          {{ ((states('sensor.heatpump_electric_consumption_w') | float(0) - 12 ) / 25) | float(0) | round(0) > 10 }}

# -- AUTOMATIONS --
# actual magic happens here

  automation:
  # -- Heatpump Controler --
  - id: '1663864767086'
    alias: Heatpump Controler
    mode: restart

    variables:
      setpoint_max: 30
      water_temp_max: 52
      water_temp_delta_max: 8
    
    trigger:
    - platform: state
      entity_id:
      - sensor.temperature_req_generic
      - sensor.opentherm_modulation_level
      - sensor.opentherm_intended_boiler_temperature
      - sensor.heatpump_capacity
      for: '00:00:10'

    action:
      
    # No heat request
    - if:
        - condition: template
          value_template: '{{ states("sensor.temperature_req_generic") |float(0) <= 0 }}'
      then:
          - condition: template
            value_template: '{{ states("input_number.heatpump_setpoint") |float(0) >= 0 }}'
          - service: input_number.set_value
            data:
              value: -1
            target:
              entity_id: input_number.heatpump_setpoint

    # Heat request (Heatpump or Gas)
      else: 

        - if:
            # Heatpump only mode (when outside temp > 4.5)
            - condition: state
              entity_id: input_boolean.heatpump_force
              state: 'on'
            - condition: template
              value_template: >-
                {{ 
                  states("sensor.smile_anna_outdoor_temperature") |float(0) > 4.5
                }}
          then:
            # Gas heating is on, try to stop it            
            - if:
                - condition: template
                  value_template: >
                    {{ 
                      states("binary_sensor.opentherm_tap_water") == "off"
                      and states("sensor.opentherm_modulation_level") |float(0) > 0 
                      and states("sensor.opentherm_return_temperature") |float(0) > 35 
                    }}
              then:
                - service: input_number.set_value
                  target:
                    entity_id: input_number.heatpump_setpoint
                  data:
                    value: -1

             # Heatpump control
              else:
                - if:
                    # throttle to 0 to keep heatpump active
                    - condition: template
                      value_template: >
                        {% set boiler_temp = states("sensor.opentherm_intended_boiler_temperature") | float(0) %}
                        {% set water_temp = states("sensor.opentherm_water_temperature") | float(0) %}
                        {% set heatpump_capacity = states("sensor.heatpump_capacity") | float(0) %}
                        {{ (boiler_temp - water_temp > water_temp_delta_max | float(0)) or (heatpump_capacity > 80) }}
                  then:
                    - service: input_number.set_value
                      target:
                        entity_id: input_number.heatpump_setpoint
                      data:
                        value:  0
                  else:
                    - if:
                      # ease on when we have a large gap because it tends to switch to Gas
                      - condition: template
                        value_template: >
                          {{ (states("sensor.opentherm_intended_boiler_temperature") | float(0) - states("sensor.opentherm_water_temperature") | float(0)) | abs   > 4.5 }}
                      then:
                        - service: input_number.set_value
                          target:
                            entity_id: input_number.heatpump_setpoint
                          data:
                            value: 0.1

                      # nu issues, just set the setpoint for faster heating
                      else:
                        - service: input_number.set_value
                          target:
                            entity_id: input_number.heatpump_setpoint
                          data:
                            value: '{{ states("sensor.temperature_req_generic") |float(0)}}'

          # Don't care about the heatpump, just set the setpoint
          else:               

            - service: input_number.set_value
              target:
                entity_id: input_number.heatpump_setpoint
              data:
                value: '{{ states("sensor.temperature_req_generic") |float(0)}}'

    # Status update
    - event: heatpump_status_value
      event_data:
        value: >-
            {% if is_state("binary_sensor.heatpump_active", "on") %}
            Warmtepomp
            {% elif states("sensor.heating_capacity") | int(0) > 0 %}
            Hybride
            {% else %}
            Inactief
            {% endif %}
    
    # Max setpoint regulation
    - if:
      - condition: template
        value_template: >-
          {{ (state_attr("climate.anna","current_temperature") |float(0) + states("input_number.heatpump_setpoint") |float(0)) 
          > setpoint_max |float(0) }}
      then:
      - service: input_number.set_value
        data:
          value: '{{ setpoint_max |float(0) - state_attr("climate.anna","current_temperature") |float(0) }}'
        target:
          entity_id: input_number.heatpump_setpoint


    # Heatpump Controler: Apply Setpoint (if it is not set yet)
    - if:
      - condition: template
        value_template: >-
          {{ state_attr("climate.anna","temperature") |float(0) |round(1) != (state_attr("climate.anna","current_temperature") |float(0) + states("input_number.heatpump_setpoint") |float(0)) |round(1) }}
      then:
      - service: climate.set_temperature
        data:
          temperature: '{{ state_attr("climate.anna","current_temperature") |float(0) + states("input_number.heatpump_setpoint") |float(0) |round(1) }}'
          #target_temp_high: 30
          #target_temp_low: 10
        target:
          entity_id: climate.anna
      - service: logbook.log
        data:
          name: Verwarming
          message: >-
            TEMP SET ( {{ state_attr("climate.anna","current_temperature") |float(0) + states("input_number.heatpump_setpoint") |float(0) |round(1) }}°C ->
            {{ state_attr("climate.anna","temperature") |float(0) }} / 
            {{ state_attr("climate.anna","current_temperature") |float(0) }}°C )
1 Like