Ignore min_cycle_duration when manually controlling the thermostat. (#16128)

* Ignore min_cycle_duration when manually controlling the thermostat.

* style

* Generic thermostat: add minimum cycle duration to keep-alive tests.

There was a bug in previous versions of the code, that would not execute
the keep-alive action if the minimum cycle duration hasn't passed.
This test verifies that the keep-alive action is executed correctly.

* Generic thermostat: added tests to verify that changing the
thermostat mode manually triggers the switch, regardless of
minimum cycle duration.

* Updated tests to use `common` module instead of the deprecated `climate`
This commit is contained in:
Lev Aronsky 2018-11-01 22:25:50 +02:00 committed by Paulus Schoutsen
parent e9ae862fca
commit 02b46e2ba3
2 changed files with 87 additions and 16 deletions

View file

@ -232,11 +232,11 @@ class GenericThermostat(ClimateDevice):
if operation_mode == STATE_HEAT:
self._current_operation = STATE_HEAT
self._enabled = True
await self._async_control_heating()
await self._async_control_heating(force=True)
elif operation_mode == STATE_COOL:
self._current_operation = STATE_COOL
self._enabled = True
await self._async_control_heating()
await self._async_control_heating(force=True)
elif operation_mode == STATE_OFF:
self._current_operation = STATE_OFF
self._enabled = False
@ -262,7 +262,7 @@ class GenericThermostat(ClimateDevice):
if temperature is None:
return
self._target_temp = temperature
await self._async_control_heating()
await self._async_control_heating(force=True)
await self.async_update_ha_state()
@property
@ -307,7 +307,7 @@ class GenericThermostat(ClimateDevice):
except ValueError as ex:
_LOGGER.error("Unable to update from sensor: %s", ex)
async def _async_control_heating(self, time=None):
async def _async_control_heating(self, time=None, force=False):
"""Check if we need to turn heating on or off."""
async with self._temp_lock:
if not self._active and None not in (self._cur_temp,
@ -320,16 +320,21 @@ class GenericThermostat(ClimateDevice):
if not self._active or not self._enabled:
return
if self.min_cycle_duration:
if self._is_device_active:
current_state = STATE_ON
else:
current_state = STATE_OFF
long_enough = condition.state(
self.hass, self.heater_entity_id, current_state,
self.min_cycle_duration)
if not long_enough:
return
if not force and time is None:
# If the `force` argument is True, we
# ignore `min_cycle_duration`.
# If the `time` argument is not none, we were invoked for
# keep-alive purposes, and `min_cycle_duration` is irrelevant.
if self.min_cycle_duration:
if self._is_device_active:
current_state = STATE_ON
else:
current_state = STATE_OFF
long_enough = condition.state(
self.hass, self.heater_entity_id, current_state,
self.min_cycle_duration)
if not long_enough:
return
too_cold = \
self._target_temp - self._cur_temp >= self._cold_tolerance
@ -385,7 +390,7 @@ class GenericThermostat(ClimateDevice):
self._is_away = True
self._saved_target_temp = self._target_temp
self._target_temp = self._away_temp
await self._async_control_heating()
await self._async_control_heating(force=True)
await self.async_update_ha_state()
async def async_turn_away_mode_off(self):
@ -394,5 +399,5 @@ class GenericThermostat(ClimateDevice):
return
self._is_away = False
self._target_temp = self._saved_target_temp
await self._async_control_heating()
await self._async_control_heating(force=True)
await self.async_update_ha_state()

View file

@ -623,6 +623,38 @@ class TestClimateGenericThermostatACModeMinCycle(unittest.TestCase):
assert SERVICE_TURN_OFF == call.service
assert ENT_SWITCH == call.data['entity_id']
def test_mode_change_ac_trigger_off_not_long_enough(self):
"""Test if mode change turns ac off despite minimum cycle."""
self._setup_switch(True)
common.set_temperature(self.hass, 30)
self.hass.block_till_done()
self._setup_sensor(25)
self.hass.block_till_done()
self.assertEqual(0, len(self.calls))
common.set_operation_mode(self.hass, climate.STATE_OFF)
self.hass.block_till_done()
self.assertEqual(1, len(self.calls))
call = self.calls[0]
self.assertEqual('homeassistant', call.domain)
self.assertEqual(SERVICE_TURN_OFF, call.service)
self.assertEqual(ENT_SWITCH, call.data['entity_id'])
def test_mode_change_ac_trigger_on_not_long_enough(self):
"""Test if mode change turns ac on despite minimum cycle."""
self._setup_switch(False)
common.set_temperature(self.hass, 25)
self.hass.block_till_done()
self._setup_sensor(30)
self.hass.block_till_done()
self.assertEqual(0, len(self.calls))
common.set_operation_mode(self.hass, climate.STATE_HEAT)
self.hass.block_till_done()
self.assertEqual(1, len(self.calls))
call = self.calls[0]
self.assertEqual('homeassistant', call.domain)
self.assertEqual(SERVICE_TURN_ON, call.service)
self.assertEqual(ENT_SWITCH, call.data['entity_id'])
def _setup_sensor(self, temp):
"""Set up the test sensor."""
self.hass.states.set(ENT_SENSOR, temp)
@ -714,6 +746,38 @@ class TestClimateGenericThermostatMinCycle(unittest.TestCase):
assert SERVICE_TURN_OFF == call.service
assert ENT_SWITCH == call.data['entity_id']
def test_mode_change_heater_trigger_off_not_long_enough(self):
"""Test if mode change turns heater off despite minimum cycle."""
self._setup_switch(True)
common.set_temperature(self.hass, 25)
self.hass.block_till_done()
self._setup_sensor(30)
self.hass.block_till_done()
self.assertEqual(0, len(self.calls))
common.set_operation_mode(self.hass, climate.STATE_OFF)
self.hass.block_till_done()
self.assertEqual(1, len(self.calls))
call = self.calls[0]
self.assertEqual('homeassistant', call.domain)
self.assertEqual(SERVICE_TURN_OFF, call.service)
self.assertEqual(ENT_SWITCH, call.data['entity_id'])
def test_mode_change_heater_trigger_on_not_long_enough(self):
"""Test if mode change turns heater on despite minimum cycle."""
self._setup_switch(False)
common.set_temperature(self.hass, 30)
self.hass.block_till_done()
self._setup_sensor(25)
self.hass.block_till_done()
self.assertEqual(0, len(self.calls))
common.set_operation_mode(self.hass, climate.STATE_HEAT)
self.hass.block_till_done()
self.assertEqual(1, len(self.calls))
call = self.calls[0]
self.assertEqual('homeassistant', call.domain)
self.assertEqual(SERVICE_TURN_ON, call.service)
self.assertEqual(ENT_SWITCH, call.data['entity_id'])
def _setup_sensor(self, temp):
"""Set up the test sensor."""
self.hass.states.set(ENT_SENSOR, temp)
@ -748,6 +812,7 @@ class TestClimateGenericThermostatACKeepAlive(unittest.TestCase):
'target_temp': 25,
'target_sensor': ENT_SENSOR,
'ac_mode': True,
'min_cycle_duration': datetime.timedelta(minutes=15),
'keep_alive': datetime.timedelta(minutes=10)
}})
@ -838,6 +903,7 @@ class TestClimateGenericThermostatKeepAlive(unittest.TestCase):
'target_temp': 25,
'heater': ENT_SWITCH,
'target_sensor': ENT_SENSOR,
'min_cycle_duration': datetime.timedelta(minutes=15),
'keep_alive': datetime.timedelta(minutes=10)
}})