diff --git a/homeassistant/components/climate/generic_thermostat.py b/homeassistant/components/climate/generic_thermostat.py index 987708834cc..6574a4d5396 100644 --- a/homeassistant/components/climate/generic_thermostat.py +++ b/homeassistant/components/climate/generic_thermostat.py @@ -13,7 +13,8 @@ from homeassistant.core import callback from homeassistant.core import DOMAIN as HA_DOMAIN from homeassistant.components.climate import ( STATE_HEAT, STATE_COOL, STATE_IDLE, ClimateDevice, PLATFORM_SCHEMA, - STATE_AUTO, SUPPORT_OPERATION_MODE, SUPPORT_TARGET_TEMPERATURE) + STATE_AUTO, ATTR_OPERATION_MODE, SUPPORT_OPERATION_MODE, + SUPPORT_TARGET_TEMPERATURE) from homeassistant.const import ( ATTR_UNIT_OF_MEASUREMENT, STATE_ON, STATE_OFF, ATTR_TEMPERATURE, CONF_NAME, ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF) @@ -40,7 +41,7 @@ CONF_MIN_DUR = 'min_cycle_duration' CONF_COLD_TOLERANCE = 'cold_tolerance' CONF_HOT_TOLERANCE = 'hot_tolerance' CONF_KEEP_ALIVE = 'keep_alive' - +CONF_INITIAL_OPERATION_MODE = 'initial_operation_mode' SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @@ -58,6 +59,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_TARGET_TEMP): vol.Coerce(float), vol.Optional(CONF_KEEP_ALIVE): vol.All( cv.time_period, cv.positive_timedelta), + vol.Optional(CONF_INITIAL_OPERATION_MODE): + vol.In([STATE_AUTO, STATE_OFF]) }) @@ -75,11 +78,12 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): cold_tolerance = config.get(CONF_COLD_TOLERANCE) hot_tolerance = config.get(CONF_HOT_TOLERANCE) keep_alive = config.get(CONF_KEEP_ALIVE) + initial_operation_mode = config.get(CONF_INITIAL_OPERATION_MODE) async_add_devices([GenericThermostat( hass, name, heater_entity_id, sensor_entity_id, min_temp, max_temp, target_temp, ac_mode, min_cycle_duration, cold_tolerance, - hot_tolerance, keep_alive)]) + hot_tolerance, keep_alive, initial_operation_mode)]) class GenericThermostat(ClimateDevice): @@ -87,7 +91,8 @@ class GenericThermostat(ClimateDevice): def __init__(self, hass, name, heater_entity_id, sensor_entity_id, min_temp, max_temp, target_temp, ac_mode, min_cycle_duration, - cold_tolerance, hot_tolerance, keep_alive): + cold_tolerance, hot_tolerance, keep_alive, + initial_operation_mode): """Initialize the thermostat.""" self.hass = hass self._name = name @@ -97,7 +102,11 @@ class GenericThermostat(ClimateDevice): self._cold_tolerance = cold_tolerance self._hot_tolerance = hot_tolerance self._keep_alive = keep_alive - self._enabled = True + self._initial_operation_mode = initial_operation_mode + if initial_operation_mode == STATE_OFF: + self._enabled = False + else: + self._enabled = True self._active = False self._cur_temp = None @@ -122,14 +131,20 @@ class GenericThermostat(ClimateDevice): @asyncio.coroutine def async_added_to_hass(self): """Run when entity about to be added.""" - # If we have an old state and no target temp, restore - if self._target_temp is None: - old_state = yield from async_get_last_state(self.hass, - self.entity_id) - if old_state is not None: + # Check If we have an old state + old_state = yield from async_get_last_state(self.hass, + self.entity_id) + if old_state is not None: + # If we have no initial temperature, restore + if self._target_temp is None: self._target_temp = float( old_state.attributes[ATTR_TEMPERATURE]) + # If we have no initial operation mode, restore + if self._initial_operation_mode is None: + if old_state.attributes[ATTR_OPERATION_MODE] == STATE_OFF: + self._enabled = False + @property def should_poll(self): """Return the polling state.""" diff --git a/tests/components/climate/test_generic_thermostat.py b/tests/components/climate/test_generic_thermostat.py index 5982a6c16d8..63bbce2e7c6 100644 --- a/tests/components/climate/test_generic_thermostat.py +++ b/tests/components/climate/test_generic_thermostat.py @@ -205,6 +205,10 @@ class TestClimateGenericThermostat(unittest.TestCase): self.hass.block_till_done() state = self.hass.states.get(ENTITY) self.assertEqual(30.0, state.attributes.get('temperature')) + climate.set_temperature(self.hass, None) + self.hass.block_till_done() + state = self.hass.states.get(ENTITY) + self.assertEqual(30.0, state.attributes.get('temperature')) def test_sensor_bad_unit(self): """Test sensor that have bad unit.""" @@ -888,19 +892,22 @@ def test_custom_setup_params(hass): 'min_temp': MIN_TEMP, 'max_temp': MAX_TEMP, 'target_temp': TARGET_TEMP, + 'initial_operation_mode': STATE_OFF, }}) assert result state = hass.states.get(ENTITY) assert state.attributes.get('min_temp') == MIN_TEMP assert state.attributes.get('max_temp') == MAX_TEMP assert state.attributes.get('temperature') == TARGET_TEMP + assert state.attributes.get(climate.ATTR_OPERATION_MODE) == STATE_OFF @asyncio.coroutine def test_restore_state(hass): """Ensure states are restored on startup.""" mock_restore_cache(hass, ( - State('climate.test_thermostat', '0', {ATTR_TEMPERATURE: "20"}), + State('climate.test_thermostat', '0', {ATTR_TEMPERATURE: "20", + climate.ATTR_OPERATION_MODE: "off"}), )) hass.state = CoreState.starting @@ -915,3 +922,29 @@ def test_restore_state(hass): state = hass.states.get('climate.test_thermostat') assert(state.attributes[ATTR_TEMPERATURE] == 20) + assert(state.attributes[climate.ATTR_OPERATION_MODE] == "off") + + +@asyncio.coroutine +def test_no_restore_state(hass): + """Ensure states are not restored on startup if not needed.""" + mock_restore_cache(hass, ( + State('climate.test_thermostat', '0', {ATTR_TEMPERATURE: "20", + climate.ATTR_OPERATION_MODE: "off"}), + )) + + hass.state = CoreState.starting + + yield from async_setup_component( + hass, climate.DOMAIN, {'climate': { + 'platform': 'generic_thermostat', + 'name': 'test_thermostat', + 'heater': ENT_SWITCH, + 'target_sensor': ENT_SENSOR, + 'target_temp': 22, + 'initial_operation_mode': 'auto', + }}) + + state = hass.states.get('climate.test_thermostat') + assert(state.attributes[ATTR_TEMPERATURE] == 22) + assert(state.attributes[climate.ATTR_OPERATION_MODE] != "off")