Integrating Hive Thermostat/Receiver, including scheduling

Sharing in a new post, this was a writeup I first shared in another thread, in the hopes someone comes along and might find this useful…

Here is my project to integrate a Hive SLR1b and SLT3 (via zigbee2mqtt) into HA including custom scheduling based on helpers/automations.

Thanks to Robert Alexa’s work on an updated converter for the Hive thermostats and associated readme over on z2m, I now have a perfectly working thermostat with some basic scheduling included. I tried Schedy but it did mad things with a whole range of entities I hadn’t asked it to (including spooky TV/music/light changes at random times!!) so I just deleted it and went with a more manual set up…

Config

I organise my config into packages, with this in configuration.yaml:

## /config/configuration.yaml

homeassistant:
  packages: !include_dir_named packages

The package:

## /config/packages/house_thermostat.yaml
## Hive Thermostat 

# Switch for frontend to toggle heat/off - with both system_mode and heating_setpoint_hold
switch:
  - platform: template
    switches:
      thermostat_mode:
        value_template: "{{ is_state('climate.house_thermostat_receiver','heat') }}"
        turn_on:
          service: mqtt.publish
          data:
            topic: zigbee2mqtt/house_thermostat_receiver/set
            payload: '{ "system_mode":"heat", "temperature_setpoint_hold":"1" }'
        turn_off:
          service: mqtt.publish
          data:
            topic: zigbee2mqtt/house_thermostat_receiver/set
            payload: '{ "system_mode":"off", "temperature_setpoint_hold":"0" }'
        icon_template: >
          {% if is_state('climate.house_thermostat_receiver','heat') %}
            mdi:fire
          {% elif is_state('climate.house_thermostat_receiver','off') %}
            mdi:power
          {% else %}
            mdi:alert
          {% endif %}

# Adds a temperature sensor to HA from the thermostat temperature
template:
  - sensor:
      name: house_thermostat_temperature
      icon: mdi:thermometer
      state: "{{ state_attr('climate.house_thermostat_receiver','local_temperature') }}"
      state_class: measurement
      unit_of_measurement: °C
      device_class: temperature

# Scheduling - input times to change temperature
input_datetime:
  thermsched_01:
    name: Thermostat Schedule 1
    icon: mdi:numeric-1-circle-outline
    has_time: true
    initial: 06:00:00
  thermsched_02:
    name: Thermostat Schedule 2
    icon: mdi:numeric-2-circle-outline
    has_time: true
    initial: 09:00:00
  thermsched_03:
    name: Thermostat Schedule 3
    icon: mdi:numeric-3-circle-outline
    has_time: true
    initial: 16:00:00
  thermsched_04:
    name: Thermostat Schedule 4
    icon: mdi:numeric-4-circle-outline
    has_time: true
    initial: 21:00:00

# Sheduling - corresponding input temperatures for each input time
input_number:
  thermtemp_01:
    name: Thermostat Temperature 1
    icon: mdi:numeric-1-circle-outline
    initial: 21
    min: 5
    max: 32
    step: 1
  thermtemp_02:
    name: Thermostat Temperature 2
    icon: mdi:numeric-2-circle-outline
    initial: 18
    min: 5
    max: 32
    step: 1
  thermtemp_03:
    name: Thermostat Temperature 3
    icon: mdi:numeric-3-circle-outline
    initial: 21
    min: 5
    max: 32
    step: 1
  thermtemp_04:
    name: Thermostat Temperature 4
    icon: mdi:numeric-4-circle-outline
    initial: 15
    min: 5
    max: 32
    step: 1

# Automations
automation:
    # Scheduling automation - change temp at corresponding time
  - id: house_thermostat_schedule
    alias: House Thermostat Schedule
    description: 'Sets house thermostat temperature based on input_datetimes and input_times'
    trigger:
      - platform: time
        at: input_datetime.thermsched_01
        id: '01'
      - platform: time
        id: '02'
        at: input_datetime.thermsched_02
      - platform: time
        id: '03'
        at: input_datetime.thermsched_03
      - platform: time
        id: '04'
        at: input_datetime.thermsched_04
    condition:
      - condition: state
        entity_id: climate.house_thermostat_receiver
        state: heat
    action:
      - choose:
          - conditions:
              - condition: trigger
                id: '01'
            sequence:
              - service: mqtt.publish
                data:
                  topic: zigbee2mqtt/house_thermostat_receiver/set
                  payload: >-
                    {"system_mode":"heat","temperature_setpoint_hold":"1","occupied_heating_setpoint":"{{ states('input_number.thermtemp_01') }}"}
          - conditions:
              - condition: trigger
                id: '02'
            sequence:
              - service: mqtt.publish
                data:
                  topic: zigbee2mqtt/house_thermostat_receiver/set
                  payload: >-
                    {"system_mode":"heat","temperature_setpoint_hold":"1","occupied_heating_setpoint":"{{ states('input_number.thermtemp_02') }}"}
          - conditions:
              - condition: trigger
                id: '03'
            sequence:
              - service: mqtt.publish
                data:
                  topic: zigbee2mqtt/house_thermostat_receiver/set
                  payload: >-
                    {"system_mode":"heat","temperature_setpoint_hold":"1","occupied_heating_setpoint":"{{ states('input_number.thermtemp_03') }}"}
          - conditions:
              - condition: trigger
                id: '04'
            sequence:
              - service: mqtt.publish
                data:
                  topic: zigbee2mqtt/house_thermostat_receiver/set
                  payload: >-
                    {"system_mode":"heat","temperature_setpoint_hold":"1","occupied_heating_setpoint":"{{ states('input_number.thermtemp_04') }}"}
        default: []
    mode: single

    # Fix accidental auto mode selection from the SLT - switch to heat mode.
    # This makes sure the HA schedule is used instead of the SLT internal one.
  - id: house_thermostat_auto_fix
    alias: House Thermostat Auto Fix
    description: 'Switches auto mode to heat mode. Maintains HA schedule rather than Hive schedule'
    trigger:
      - platform: state
        entity_id: climate.house_thermostat_receiver
        to: auto
    condition: []
    action:
      - service: mqtt.publish
        data:
            topic: zigbee2mqtt/house_thermostat_receiver/set
            payload: '{ "system_mode":"heat", "temperature_setpoint_hold":"1" }'
    mode: single

Note: I have SLR1b and SLT3. entities climate.house_thermostat_receiver and climate.house_thermostat.

Lovelace cards

I have a few custom cards included stack-in-card, simple-thermostat, mini-graph-card, and slider-entity-row

For basic thermostat control, on my wall tablets, I have this card:

type: custom:stack-in-card
mode: horizontal
cards:
  - type: custom:stack-in-card
    cards:
      - type: button
        entity: switch.thermostat_mode
        tap_action:
          action: toggle
        hold_action:
          action: more-info
        show_name: false
        show_icon: true
        show_state: false
        icon_height: 30px
      - type: conditional
        conditions:
          - entity: climate.house_thermostat_receiver
            state: heat
        card:
          type: custom:simple-thermostat
          entity: climate.house_thermostat_receiver
          header: false
          layout:
            mode:
              names: false
              headings: false
              icons: true
            step: column
          step_size: '0.5'
          decimals: '1'
          control: false
          sensors: false
  - align_header: right
    color_thresholds:
      - color: '#4B88B0'
        value: 16
      - color: '#e7710f'
        value: 20
      - color: '#FC0E34'
        value: 24
    decimals: 1
    entities:
      - sensor.house_thermostat_temperature
    font_size: 75
    hours_to_show: 24
    show:
      icon: false
    name: Lounge
    type: custom:mini-graph-card
card_mod:
  style: |
    ha-card {
      --ha-card-background: #04021C;
    }

Which looks like this when on:
image
and like this when off:
image

To adjust the scheduling, I then have this card in a popup_card when long pressing the switch, and other dashboards I use on desktop:

type: entities
entities:
  - entity: input_datetime.thermsched_01
  - type: custom:slider-entity-row
    entity: input_number.thermtemp_01
    full_row: true
  - entity: input_datetime.thermsched_02
  - type: custom:slider-entity-row
    entity: input_number.thermtemp_02
    full_row: true
  - entity: input_datetime.thermsched_03
  - type: custom:slider-entity-row
    entity: input_number.thermtemp_03
    full_row: true
  - entity: input_datetime.thermsched_04
  - type: custom:slider-entity-row
    entity: input_number.thermtemp_04
    full_row: true

Which looks like this:
image

We find we don’t need any additional schedule changes, or different between weekday/weekend (joys of working from home!)… but extra schedule times should be simple enough to implement, and with a workday sensor, and/or additional input_datetime it should be fairly straightforward to make much more complex schedules.

Still to do:

  • find a way to set temp based on current/last temperature when turning it on - as manually toggling the heating now reverts to 19C when turned on. I imagine we might never turn heating on/off, except at the end of winter - instead simply setting a lower temperature when away, for frost protection (Hive may automatically do this with its internal frost level? I need to investigate).
  • lower the temperature when we leave the house/preheat when we’re coming home. to do this, I’m working on a granular home occupancy state based on our distance from home (eg going for a walk near home = only lower temp a little bit, going to visit friends for the night = lower temp completely, etc etc). Currently my basic away mode just turns the heating off - not ideal when we’re out for the day and its freezing when we arrive home.
  • Integrate boost mode using the SLT’s boost button and/or a custom HA button. I think I will have to find a way to template the current temperature based on last input_datetime time so this can be recalled at the end of the boost time.