Skip to content

Commit

Permalink
Add set_operation_mode support to generic_thermostat (#8392)
Browse files Browse the repository at this point in the history
This commit adds support for the set_operation_mode system call to the
generic thermostat component. This enables users to set whether the
thermostat is enabled or not by either setting it to auto or off.
  • Loading branch information
mtreinish authored and balloob committed Jul 8, 2017
1 parent c5bf4fe commit cb29812
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 1 deletion.
28 changes: 27 additions & 1 deletion homeassistant/components/climate/generic_thermostat.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
from homeassistant.core import callback
from homeassistant.components import switch
from homeassistant.components.climate import (
STATE_HEAT, STATE_COOL, STATE_IDLE, ClimateDevice, PLATFORM_SCHEMA)
STATE_HEAT, STATE_COOL, STATE_IDLE, ClimateDevice, PLATFORM_SCHEMA,
STATE_AUTO)
from homeassistant.const import (
ATTR_UNIT_OF_MEASUREMENT, STATE_ON, STATE_OFF, ATTR_TEMPERATURE,
CONF_NAME)
Expand Down Expand Up @@ -87,6 +88,7 @@ def __init__(self, hass, name, heater_entity_id, sensor_entity_id,
self.min_cycle_duration = min_cycle_duration
self._tolerance = tolerance
self._keep_alive = keep_alive
self._enabled = True

self._active = False
self._cur_temp = None
Expand Down Expand Up @@ -131,6 +133,8 @@ def current_temperature(self):
@property
def current_operation(self):
"""Return current operation ie. heat, cool, idle."""
if not self._enabled:
return STATE_OFF
if self.ac_mode:
cooling = self._active and self._is_device_active
return STATE_COOL if cooling else STATE_IDLE
Expand All @@ -143,6 +147,25 @@ def target_temperature(self):
"""Return the temperature we try to reach."""
return self._target_temp

@property
def operation_list(self):
"""List of available operation modes."""
return [STATE_AUTO, STATE_OFF]

def set_operation_mode(self, operation_mode):
"""Set operation mode."""
if operation_mode == STATE_AUTO:
self._enabled = True
elif operation_mode == STATE_OFF:
self._enabled = False
if self._is_device_active:
switch.async_turn_off(self.hass, self.heater_entity_id)
else:
_LOGGER.error('Unrecognized operation mode: %s', operation_mode)
return
# Ensure we updae the current operation after changing the mode
self.schedule_update_ha_state()

@asyncio.coroutine
def async_set_temperature(self, **kwargs):
"""Set new target temperature."""
Expand Down Expand Up @@ -221,6 +244,9 @@ def _async_control_heating(self):
if not self._active:
return

if not self._enabled:
return

if self.min_cycle_duration:
if self._is_device_active:
current_state = STATE_ON
Expand Down
54 changes: 54 additions & 0 deletions tests/components/climate/test_generic_thermostat.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ def test_default_setup_params(self):
self.assertEqual(35, state.attributes.get('max_temp'))
self.assertEqual(None, state.attributes.get('temperature'))

def test_get_operation_modes(self):
"""Test that the operation list returns the correct modes."""
state = self.hass.states.get(ENTITY)
modes = state.attributes.get('operation_list')
self.assertEqual([climate.STATE_AUTO, STATE_OFF], modes)

def test_set_target_temp(self):
"""Test the setting of the target temperature."""
climate.set_temperature(self.hass, 30)
Expand Down Expand Up @@ -211,6 +217,30 @@ def test_temp_change_heater_off_outside_tolerance(self):
self.assertEqual(SERVICE_TURN_OFF, call.service)
self.assertEqual(ENT_SWITCH, call.data['entity_id'])

def test_running_when_operating_mode_is_off(self):
"""Test that the switch turns off when enabled is set False."""
self._setup_switch(True)
climate.set_temperature(self.hass, 30)
self.hass.block_till_done()
climate.set_operation_mode(self.hass, STATE_OFF)
self.hass.block_till_done()
self.assertEqual(1, len(self.calls))
call = self.calls[0]
self.assertEqual('switch', call.domain)
self.assertEqual(SERVICE_TURN_OFF, call.service)
self.assertEqual(ENT_SWITCH, call.data['entity_id'])

def test_no_state_change_when_operation_mode_off(self):
"""Test that the switch doesn't turn on when enabled is False."""
self._setup_switch(False)
climate.set_temperature(self.hass, 30)
self.hass.block_till_done()
climate.set_operation_mode(self.hass, STATE_OFF)
self.hass.block_till_done()
self._setup_sensor(25)
self.hass.block_till_done()
self.assertEqual(0, len(self.calls))

def _setup_sensor(self, temp, unit=TEMP_CELSIUS):
"""Setup the test sensor."""
self.hass.states.set(ENT_SENSOR, temp, {
Expand Down Expand Up @@ -321,6 +351,30 @@ def test_temp_change_ac_on_outside_tolerance(self):
self.assertEqual(SERVICE_TURN_ON, call.service)
self.assertEqual(ENT_SWITCH, call.data['entity_id'])

def test_running_when_operating_mode_is_off(self):
"""Test that the switch turns off when enabled is set False."""
self._setup_switch(True)
climate.set_temperature(self.hass, 30)
self.hass.block_till_done()
climate.set_operation_mode(self.hass, STATE_OFF)
self.hass.block_till_done()
self.assertEqual(1, len(self.calls))
call = self.calls[0]
self.assertEqual('switch', call.domain)
self.assertEqual(SERVICE_TURN_OFF, call.service)
self.assertEqual(ENT_SWITCH, call.data['entity_id'])

def test_no_state_change_when_operation_mode_off(self):
"""Test that the switch doesn't turn on when enabled is False."""
self._setup_switch(False)
climate.set_temperature(self.hass, 30)
self.hass.block_till_done()
climate.set_operation_mode(self.hass, STATE_OFF)
self.hass.block_till_done()
self._setup_sensor(35)
self.hass.block_till_done()
self.assertEqual(0, len(self.calls))

def _setup_sensor(self, temp, unit=TEMP_CELSIUS):
"""Setup the test sensor."""
self.hass.states.set(ENT_SENSOR, temp, {
Expand Down

0 comments on commit cb29812

Please sign in to comment.