Skip to content

Commit

Permalink
feat: implements dryer hvac device
Browse files Browse the repository at this point in the history
  • Loading branch information
= authored and swingerman committed May 28, 2024
1 parent 9ade24e commit 4e64666
Show file tree
Hide file tree
Showing 13 changed files with 212 additions and 40 deletions.
45 changes: 45 additions & 0 deletions config/configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ input_boolean:
name: Cooler toggle
fan_on:
name: Fan toggle
dryer_on:
name: Fan toggle
window_open:
name: Window
window_open2:
Expand Down Expand Up @@ -41,6 +43,14 @@ input_number:
step: .1
icon: mdi:thermometer-lines

humidity:
name: humidity
initial: 40
min: 20
max: 90
step: .1
icon: mdi:thermometer-water

sensor:
- platform: template
sensors:
Expand All @@ -50,6 +60,12 @@ sensor:
floor_temp:
value_template: "{{ states.input_number.room_floor_temp.state | int | round(1) }}"
entity_id: input_number.room_floor_temp
outside_temp:
value_template: "{{ states.input_number.outside_temp.state | int | round(1) }}"
entity_id: input_number.outside_temp
humidity:
value_template: "{{ states.input_number.humidity.state | int | round(1) }}"
entity_id: input_number.humidity

switch:
- platform: template
Expand Down Expand Up @@ -98,6 +114,17 @@ switch:
data:
entity_id: input_boolean.fan_on

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

window:
value_template: "{{ is_state('input_boolean.window_open', 'on') }}"
turn_on:
Expand Down Expand Up @@ -329,6 +356,24 @@ climate:
cold_tolerance: 0.3
hot_tolerance: 0.3

- platform: dual_smart_thermostat
name: Dual Humidity
unique_id: dual_humidity
heater: switch.heater
cooler: switch.cooler
dryer: switch.dryer
target_sensor: sensor.room_temp
humidity_sensor: sensor.humidity
heat_cool_mode: true
target_temp_step: 0.1
target_sensor_safety_delay: "00:10"
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
20 changes: 19 additions & 1 deletion custom_components/dual_smart_thermostat/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,9 @@ def __init__(
self._target_temp_low = self.environment.target_temp_low
self._attr_temperature_unit = unit

self._target_humidity = self.environment.target_humidity
self._cur_humidity = self.environment.cur_humidity

self._unit = unit

# HVAC modes
Expand Down Expand Up @@ -646,6 +649,11 @@ def current_humidity(self) -> float | None:
"""Return the sensor humidity."""
return self.environment.cur_humidity

@property
def target_humidity(self) -> float | None:
"""Return the target humidity."""
return self.environment.target_humidity

@property
def current_floor_temperature(self) -> float | None:
"""Return the sensor temperature."""
Expand Down Expand Up @@ -770,6 +778,7 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:

self._hvac_mode = hvac_mode
self._set_support_flags()
self._target_humidity = self.environment.target_humidity

await self.hvac_device.async_set_hvac_mode(hvac_mode)

Expand Down Expand Up @@ -801,6 +810,15 @@ async def async_set_temperature(self, **kwargs) -> None:
await self._async_control_climate(force=True)
self.async_write_ha_state()

async def async_set_humidity(self, humidity: float) -> None:
"""Set new target humidity."""
_LOGGER.debug("Setting humidity: %s", humidity)
self.environment.target_humidity = humidity
self._target_humidity = self.environment.target_humidity

await self._async_control_climate(force=True)
self.async_write_ha_state()

def _set_temperatures_dual_mode(self, temperatures: TargetTemperatures) -> None:
"""Set new target temperature for dual mode."""
temperature = temperatures.temperature
Expand Down Expand Up @@ -871,7 +889,7 @@ async def _async_sensor_humidity_changed(
if new_state is None or new_state.state in (STATE_UNAVAILABLE, STATE_UNKNOWN):
return

self.environment.update_floor_temp_from_state(new_state)
self.environment.update_humidity_from_state(new_state)
await self._async_control_climate()
self.async_write_ha_state()

Expand Down
4 changes: 3 additions & 1 deletion custom_components/dual_smart_thermostat/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@
CONF_AUX_HEATING_DUAL_MODE = "secondary_heater_dual_mode"
CONF_COOLER = "cooler"

CONF_DEHUMIDIFIER = "dehumidifier"
CONF_DRYER = "dryer"
CONF_MIN_HUMIDITY = "min_humidity"
CONF_MAX_HUMIDITY = "max_humidity"
CONF_TARGET_HUMIDITY = "target_humidity"
CONF_DRY_TOLERANCE = "dry_tolerance"
CONF_MOIST_TOLERANCE = "moist_tolerance"
CONF_HUMIDITY_SENSOR = "humidity_sensor"

CONF_FAN = "fan"
CONF_FAN_MODE = "fan_mode"
Expand Down Expand Up @@ -99,4 +100,5 @@ class ToleranceDevice(enum.StrEnum):

HEATER = "heater"
COOLER = "cooler"
DRYER = "dryer"
AUTO = "auto"
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ def __init__(
)

@property
def target_temp_attr(self) -> str:
def target_env_attr(self) -> str:
return (
"_target_temp_high"
if self.features.is_range_mode
else self._target_temp_attr
else self._target_env_attr
)

@property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ async def async_control_hvac(self, time=None, force=False):
else:

is_within_fan_tolerance = self.environment.is_within_fan_tolerance(
self.fan_device.target_temp_attr
self.fan_device.target_env_attr
)
is_warmer_outside = self.environment.is_warmer_outside
is_fan_air_outside = self.fan_device.fan_air_surce_outside
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import logging

from homeassistant.components.climate import HVACAction, HVACMode

from custom_components.dual_smart_thermostat.hvac_device.specific_hvac_device import (
SpecificHVACDevice,
)

_LOGGER = logging.getLogger(__name__)


class DryerDevice(SpecificHVACDevice):

_target_env_attr: str = "_target_humidity"

hvac_modes = [HVACMode.DRY, HVACMode.OFF]

def __init__(
self,
hass,
entity_id,
min_cycle_duration,
initial_hvac_mode,
environment,
openings,
features,
) -> None:
super().__init__(
hass,
entity_id,
min_cycle_duration,
initial_hvac_mode,
environment,
openings,
features,
)

@property
def hvac_action(self) -> HVACAction:
if self.hvac_mode == HVACMode.OFF:
return HVACAction.OFF
if self.is_active:
return HVACAction.DRYING
return HVACAction.IDLE

def _set_self_active(self) -> None:
"""Checks if active state needs to be set true."""
_LOGGER.debug("_active: %s", self._active)
_LOGGER.debug("cur_humidity: %s", self.environment.cur_humidity)
_LOGGER.debug("target_env_attr: %s", self.target_env_attr)
target_humidity = getattr(self.environment, self.target_env_attr)
_LOGGER.debug("target_humidity: %s", target_humidity)

if (
not self._active
and None not in (self.environment.cur_humidity, target_humidity)
and self._hvac_mode != HVACMode.OFF
):
self._active = True
_LOGGER.debug(
"Obtained current and target temperature. Device active. %s, %s",
self.environment.cur_humidity,
target_humidity,
)

def is_below_target_env_attr(self) -> bool:
"""is too dry?"""
return self.environment.is_too_dry

def is_above_target_env_attr(self) -> bool:
"""is too moist?"""
return self.environment.is_too_moist
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

class HeaterAUXHeaterDevice(MultiHvacDevice):

_target_temp_attr: str = "_target_temp"
_target_env_attr: str = "_target_temp"

def __init__(
self,
Expand All @@ -52,7 +52,7 @@ def __init__(
self._aux_heater_dual_mode = self._features.aux_heater_dual_mode

if features.is_range_mode:
self._target_temp_attr = "_target_temp_low"
self._target_env_attr = "_target_temp_low"

self._aux_heater_last_run: datetime = None

Expand Down Expand Up @@ -83,7 +83,7 @@ async def _async_control_devices_when_off(self, time=None) -> None:
"""Check if we need to turn heating on or off when the heater is off."""
_LOGGER.debug("%s _async_control_devices_when_off", self.__class__.__name__)

too_cold = self.environment.is_too_cold(self._target_temp_attr)
too_cold = self.environment.is_too_cold(self._target_env_attr)
is_floor_hot = self.environment.is_floor_hot
is_floor_cold = self.environment.is_floor_cold
any_opening_open = self.openings.any_opening_open(self.hvac_mode)
Expand Down Expand Up @@ -138,7 +138,7 @@ async def _async_control_devices_when_on(self, time=None) -> None:
"""Check if we need to turn heating on or off when the heater is off."""
_LOGGER.debug("%s _async_control_devices_when_on", self.__class__.__name__)

too_hot = self.environment.is_too_hot(self._target_temp_attr)
too_hot = self.environment.is_too_hot(self._target_env_attr)
is_floor_hot = self.environment.is_floor_hot
is_floor_cold = self.environment.is_floor_cold
any_opening_open = self.openings.any_opening_open(self.hvac_mode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,9 @@ def __init__(
)

@property
def target_temp_attr(self) -> str:
def target_env_attr(self) -> str:
return (
"_target_temp_low"
if self.features.is_range_mode
else self._target_temp_attr
"_target_temp_low" if self.features.is_range_mode else self._target_env_attr
)

@property
Expand Down Expand Up @@ -84,7 +82,7 @@ async def async_control_hvac(self, time=None, force=False):

async def _async_control_device_when_on(self, time=None) -> None:
"""Check if we need to turn heating on or off when theheater is on."""
too_hot = self.environment.is_too_hot(self.target_temp_attr)
too_hot = self.environment.is_too_hot(self.target_env_attr)
is_floor_hot = self.environment.is_floor_hot
is_floor_cold = self.environment.is_floor_cold
is_sensor_safety_timed_out = self.environment.is_sensor_safety_timed_out
Expand Down Expand Up @@ -131,7 +129,7 @@ async def _async_control_device_when_off(self, time=None) -> None:
"""Check if we need to turn heating on or off when the heater is off."""
_LOGGER.debug("%s _async_control_device_when_off", self.__class__.__name__)

too_cold = self.environment.is_too_cold(self.target_temp_attr)
too_cold = self.environment.is_too_cold(self.target_env_attr)
is_floor_hot = self.environment.is_floor_hot
is_floor_cold = self.environment.is_floor_cold
any_opening_open = self.openings.any_opening_open(self.hvac_mode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ async def async_turn_off(self):
pass


class CanTargetTemperature(ABC):
class TargetsEnvironmentAttribute(ABC):

_target_temp_attr: str = "_target_temp"
_target_env_attr: str = "_target_temp"

@property
@abstractmethod
def target_temp_attr(self) -> str:
def target_env_attr(self) -> str:
pass


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
CONF_AUX_HEATING_DUAL_MODE,
CONF_AUX_HEATING_TIMEOUT,
CONF_COOLER,
CONF_DRYER,
CONF_FAN,
CONF_FAN_ON_WITH_AC,
CONF_HEATER,
Expand All @@ -24,6 +25,7 @@
from custom_components.dual_smart_thermostat.hvac_device.cooler_fan_device import (
CoolerFanDevice,
)
from custom_components.dual_smart_thermostat.hvac_device.dryer_device import DryerDevice
from custom_components.dual_smart_thermostat.hvac_device.fan_device import FanDevice
from custom_components.dual_smart_thermostat.hvac_device.heater_aux_heater_device import (
HeaterAUXHeaterDevice,
Expand Down Expand Up @@ -73,6 +75,8 @@ def __init__(
self._fan_entity_id = config.get(CONF_FAN)
self._fan_on_with_cooler = config.get(CONF_FAN_ON_WITH_AC)

self._dryer_entity_id = config.get(CONF_DRYER)

self._aux_heater_entity_id = config.get(CONF_AUX_HEATER)
self._aux_heater_dual_mode = config.get(CONF_AUX_HEATING_DUAL_MODE)
self._aux_heater_timeout = config.get(CONF_AUX_HEATING_TIMEOUT)
Expand Down Expand Up @@ -297,6 +301,19 @@ def _create_heat_cool_device(
)
)

if features.is_configured_for_dryer_mode:
devices.append(
DryerDevice(
self.hass,
self._dryer_entity_id,
self._min_cycle_duration,
self._initial_hvac_mode,
environment,
openings,
features,
)
)

return MultiHvacDevice(
self.hass,
devices,
Expand Down
Loading

0 comments on commit 4e64666

Please sign in to comment.