Skip to content

Commit

Permalink
fix: correctly handles and communicates hvac modes
Browse files Browse the repository at this point in the history
Fixes #20
  • Loading branch information
= authored and swingerman committed May 25, 2022
1 parent cff72b7 commit b624257
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 21 deletions.
21 changes: 21 additions & 0 deletions .devcontainer/configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,27 @@ climate:
away_temp: 16
precision: 0.1

- platform: generic_thermostat
name: generic one
unique_id: generic_cool
heater: switch.cooler
ac_mode: true
target_sensor: sensor.room_temp
min_temp: 15
max_temp: 28
target_temp: 23
target_temp_high: 26
target_temp_low: 23
cold_tolerance: 0.3
hot_tolerance: 0
min_cycle_duration:
seconds: 5
keep_alive:
minutes: 3
# initial_hvac_mode: "off"
away_temp: 16
precision: 0.1

logger:
default: error
logs:
Expand Down
60 changes: 43 additions & 17 deletions custom_components/dual_smart_thermostat/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
DEFAULT_MAX_FLOOR_TEMP,
DEFAULT_NAME,
DEFAULT_TOLERANCE,
HVACAction,
HVACMode,
)

Expand Down Expand Up @@ -439,14 +440,14 @@ def hvac_action(self):
Need to be one of CURRENT_HVAC_*.
"""
if self._hvac_mode == HVACMode.OFF:
return HVACMode.OFF
return HVACAction.OFF
if not self._is_device_active:
return HVACMode.IDLE
return HVACAction.IDLE
if self.ac_mode:
return HVACMode.COOL
return HVACAction.COOLING
if self._is_cooler_active:
return HVACMode.COOL
return HVACMode.HEAT
return HVACAction.COOLING
return HVACAction.HEATING

@property
def target_temperature(self):
Expand Down Expand Up @@ -649,6 +650,9 @@ async def _async_control_heating(self, time=None, force=False):
too_cold = self._is_too_cold()
too_hot = self._is_too_hot()

if self.cooler_entity_id and self._is_cooler_active:
await self._async_cooler_turn_off()

if self._is_device_active:
if too_hot or self._is_floor_hot or self._is_opening_open:
_LOGGER.info("Turning off heater %s", self.heater_entity_id)
Expand Down Expand Up @@ -689,29 +693,32 @@ async def _async_control_cooling(self, time=None, force=False):
too_cold = self._is_too_cold()
too_hot = self._is_too_hot()

cooler_entity = self.heater_entity_id

if not self.ac_mode and self.cooler_entity_id:
cooler_entity = self.cooler_entity_id
if self._is_heter_active:
await self._async_heater_turn_off()

if self._is_device_active:
if too_cold or self._is_opening_open:
_LOGGER.info("Turning off cooler %s", self.heater_entity_id)
await self._async_heater_turn_off()
_LOGGER.info("Turning off cooler %s", cooler_entity)
await self._async_switch_turn_off(cooler_entity)
elif time is not None and not self._is_opening_open:
# The time argument is passed only in keep-alive case
_LOGGER.info(
"Keep-alive - Turning on cooler (from active) %s",
self.heater_entity_id,
cooler_entity,
)
await self._async_heater_turn_on()
await self._async_switch_turn_on(cooler_entity)
else:
if too_hot and not self._is_opening_open:
_LOGGER.info(
"Turning on cooler (from inactive) %s", self.heater_entity_id
)
await self._async_heater_turn_on()
_LOGGER.info("Turning on cooler (from inactive) %s", cooler_entity)
await self._async_switch_turn_on(cooler_entity)
elif time is not None or self._is_opening_open or self._is_floor_hot:
# The time argument is passed only in keep-alive case
_LOGGER.info(
"Keep-alive - Turning off cooler %s", self.heater_entity_id
)
await self._async_heater_turn_off()
_LOGGER.info("Keep-alive - Turning off cooler %s", cooler_entity)
await self._async_switch_turn_off(cooler_entity)

async def _async_control_heat_cool(self, time=None, force=False):
"""Check if we need to turn heating on or off."""
Expand Down Expand Up @@ -795,6 +802,11 @@ def _is_device_active(self):
and self.hass.states.is_state(self.cooler_entity_id, STATE_ON)
)

@property
def _is_heter_active(self):
"""If the toggleable device is currently active."""
return self.hass.states.is_state(self.heater_entity_id, STATE_ON)

@property
def _is_cooler_active(self):
"""If the toggleable cooler device is currently active."""
Expand Down Expand Up @@ -840,6 +852,20 @@ async def _async_cooler_turn_off(self):
HA_DOMAIN, SERVICE_TURN_OFF, data, context=self._context
)

async def _async_switch_turn_off(self, entity_id):
"""Turn toggleable device off."""
data = {ATTR_ENTITY_ID: entity_id}
await self.hass.services.async_call(
HA_DOMAIN, SERVICE_TURN_OFF, data, context=self._context
)

async def _async_switch_turn_on(self, entity_id):
"""Turn toggleable device off."""
data = {ATTR_ENTITY_ID: entity_id}
await self.hass.services.async_call(
HA_DOMAIN, SERVICE_TURN_ON, data, context=self._context
)

async def async_set_preset_mode(self, preset_mode: str):
"""Set new preset mode."""
if preset_mode == PRESET_AWAY and not self._is_away:
Expand Down
11 changes: 11 additions & 0 deletions custom_components/dual_smart_thermostat/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,14 @@ class HVACMode(StrEnum):
FAN_ONLY = "fan_only"

IDLE = "idle"


class HVACAction(StrEnum):
"""HVAC action for climate devices."""

COOLING = "cooling"
DRYING = "drying"
FAN = "fan"
HEATING = "heating"
IDLE = "idle"
OFF = "off"
3 changes: 0 additions & 3 deletions hacs.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
"name": "Dual Smart Thermostat",
"render_readme": true,
"hide_default_branch": true,
"domains": [
"climate"
],
"country": [],
"homeassistant": "0.118.0",
"filename": "ha-dual-smart-thermostat.zip"
Expand Down
2 changes: 1 addition & 1 deletion tests/test_thermostat.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,8 @@ async def test_heater_cooler_switch_hvac_modes(hass, setup_comp_1):

_setup_sensor(hass, temp_input, 26)
await hass.async_block_till_done()
await async_set_hvac_mode(hass, "all", HVACMode.HEAT)

await async_set_hvac_mode(hass, "all", HVACMode.HEAT)
assert hass.states.get("climate.test").state == HVAC_MODE_HEAT

await async_set_hvac_mode(hass, "all", HVACMode.COOL)
Expand Down

0 comments on commit b624257

Please sign in to comment.