Skip to content

Commit

Permalink
feat: heat pump mode (dual with only one switch)
Browse files Browse the repository at this point in the history
Fixes #143
  • Loading branch information
= committed Jul 23, 2024
1 parent 998b9a8 commit 63aea6d
Show file tree
Hide file tree
Showing 27 changed files with 1,825 additions and 238 deletions.
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
{
"python.pythonPath": "/usr/bin/python3",
"python.formatting.provider": "black",
"editor.formatOnSave": true,
"python.analysis.diagnosticSeverityOverrides": {},
"python.analysis.indexing": true,
"python.analysis.autoImportCompletions": true,
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.formatOnSave": true
}
}
29 changes: 29 additions & 0 deletions config/configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ input_boolean:
name: Fan toggle
dryer_on:
name: Fan toggle
heat_pump_cool:
name: Heat Pump Heat toggle
window_open:
name: Window
window_open2:
Expand Down Expand Up @@ -125,6 +127,17 @@ switch:
data:
entity_id: input_boolean.dryer_on

heat_pump_cool:
value_template: "{{ is_state('input_boolean.heat_pump_cool', 'on') }}"
turn_on:
service: input_boolean.turn_on
data:
entity_id: input_boolean.heat_pump_cool
turn_off:
service: input_boolean.turn_off
data:
entity_id: input_boolean.heat_pump_cool

window:
value_template: "{{ is_state('input_boolean.window_open', 'on') }}"
turn_on:
Expand Down Expand Up @@ -465,6 +478,22 @@ climate:
target_temp_low: 18
humidity: 60

- platform: dual_smart_thermostat
name: Dual Heat Pump
unique_id: dual_heat_pump
heater: switch.heater
target_sensor: sensor.room_temp
heat_pump_cooling: switch.heat_pump_cool
heat_cool_mode: true
target_temp_step: 0.1
precision: 0.1
min_temp: 9
max_temp: 32
target_temp: 20
cold_tolerance: 0.3
hot_tolerance: 0.3


# - platform: dual_smart_thermostat
# name: AUX Heat Room
# unique_id: aux_heat_room
Expand Down
47 changes: 47 additions & 0 deletions custom_components/dual_smart_thermostat/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
CONF_FAN_ON_WITH_AC,
CONF_FLOOR_SENSOR,
CONF_HEAT_COOL_MODE,
CONF_HEAT_PUMP_COOLING,
CONF_HEATER,
CONF_HOT_TOLERANCE,
CONF_HUMIDITY_SENSOR,
Expand Down Expand Up @@ -187,6 +188,10 @@
vol.Optional(CONF_MOIST_TOLERANCE): vol.Coerce(float),
}

HEAT_PUMP_SCHEMA = {
vol.Optional(CONF_HEAT_PUMP_COOLING): cv.entity_id,
}

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_HEATER): cv.entity_id,
Expand Down Expand Up @@ -238,6 +243,8 @@

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(HYGROSTAT_SCHEMA)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(HEAT_PUMP_SCHEMA)

# Add the old presets schema to avoid breaking change
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{vol.Optional(v): vol.Coerce(float) for (k, v) in CONF_PRESETS_OLD.items()}
Expand All @@ -260,6 +267,7 @@ async def async_setup_platform(
sensor_outside_entity_id = config.get(CONF_OUTSIDE_SENSOR)
sensor_humidity_entity_id = config.get(CONF_HUMIDITY_SENSOR)
sensor_stale_duration: timedelta | None = config.get(CONF_STALE_DURATION)
sensor_heat_pump_cooling_entity_id = config.get(CONF_HEAT_PUMP_COOLING)
keep_alive = config.get(CONF_KEEP_ALIVE)

precision = config.get(CONF_PRECISION)
Expand Down Expand Up @@ -290,6 +298,7 @@ async def async_setup_platform(
sensor_outside_entity_id,
sensor_humidity_entity_id,
sensor_stale_duration,
sensor_heat_pump_cooling_entity_id,
keep_alive,
precision,
unit,
Expand Down Expand Up @@ -343,6 +352,7 @@ def __init__(
sensor_outside_entity_id,
sensor_humidity_entity_id,
sensor_stale_duration,
sensor_heat_pump_cooling_entity_id,
keep_alive,
precision,
unit,
Expand Down Expand Up @@ -378,6 +388,7 @@ def __init__(
self.sensor_floor_entity_id = sensor_floor_entity_id
self.sensor_outside_entity_id = sensor_outside_entity_id
self.sensor_humidity_entity_id = sensor_humidity_entity_id
self.sensor_heat_pump_cooling_entity_id = sensor_heat_pump_cooling_entity_id

self._keep_alive = keep_alive

Expand Down Expand Up @@ -473,6 +484,19 @@ async def async_added_to_hass(self) -> None:
)
)

if self.sensor_heat_pump_cooling_entity_id is not None:
_LOGGER.debug(
"Adding heat pump cooling sensor listener: %s",
self.sensor_heat_pump_cooling_entity_id,
)
self.async_on_remove(
async_track_state_change_event(
self.hass,
[self.sensor_heat_pump_cooling_entity_id],
self._async_entity_heat_pump_cooling_changed_event,
)
)

if self._keep_alive:
self.async_on_remove(
async_track_time_interval(
Expand Down Expand Up @@ -868,6 +892,8 @@ def _set_temperatures_dual_mode(self, temperatures: TargetTemperatures) -> None:
temp_low = temperatures.temp_low
temp_high = temperatures.temp_high

self.hvac_device.on_target_temperature_change(temperatures)

if self.features.is_target_mode:
if temperature is None:
return
Expand Down Expand Up @@ -1028,6 +1054,27 @@ async def _async_sensor_humidity_changed(
await self._async_control_climate()
self.async_write_ha_state()

async def _async_entity_heat_pump_cooling_changed_event(
self, event: Event[EventStateChangedData]
) -> None:
data = event.data

self.hvac_device.on_entity_state_changed(data["entity_id"], data["new_state"])

await self._asyn_entity_heat_pump_cooling_changed(data["new_state"])
self._attr_hvac_modes = self.hvac_device.hvac_modes
self.async_write_ha_state()

async def _asyn_entity_heat_pump_cooling_changed(
self, new_state: State | None, trigger_control=True
) -> None:
"""Handle heat pump cooling changes."""
_LOGGER.info("Entity heat pump cooling change: %s", new_state)

if trigger_control:
await self._async_control_climate()
self.async_write_ha_state()

async def _check_device_initial_state(self) -> None:
"""Prevent the device from keep running if HVACMode.OFF."""
_LOGGER.debug("Checking device initial state")
Expand Down
1 change: 1 addition & 0 deletions custom_components/dual_smart_thermostat/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
CONF_OPENINGS = "openings"
CONF_OPENINGS_SCOPE = "openings_scope"
CONF_HEAT_COOL_MODE = "heat_cool_mode"
CONF_HEAT_PUMP_COOLING = "heat_pump_cooling"

ATTR_PREV_TARGET = "prev_target_temp"
ATTR_PREV_TARGET_LOW = "prev_target_temp_low"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Hvac Action Reason Module"""
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""HVAC controller module for Dual Smart Thermostat."""
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from datetime import timedelta
import logging
from typing import Callable

from homeassistant.core import HomeAssistant

from custom_components.dual_smart_thermostat.hvac_controller.generic_controller import (
GenericHvacController,
)
from custom_components.dual_smart_thermostat.managers.environment_manager import (
EnvironmentManager,
)
from custom_components.dual_smart_thermostat.managers.opening_manager import (
OpeningManager,
)

_LOGGER = logging.getLogger(__name__)


class CoolerHvacController(GenericHvacController):

def __init__(
self,
hass: HomeAssistant,
entity_id,
min_cycle_duration: timedelta,
environment: EnvironmentManager,
openings: OpeningManager,
turn_on_callback: Callable,
turn_off_callback: Callable,
) -> None:
self._controller_type = self.__class__.__name__

super().__init__(
hass,
entity_id,
min_cycle_duration,
environment,
openings,
turn_on_callback,
turn_off_callback,
)
Loading

0 comments on commit 63aea6d

Please sign in to comment.