From 43ae96b774c805100d441168b395bfd4ecf068b6 Mon Sep 17 00:00:00 2001 From: ziotibia81 Date: Fri, 17 Nov 2017 14:15:11 +0100 Subject: [PATCH 01/10] Update generic_thermostat.py --- .../components/climate/generic_thermostat.py | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/climate/generic_thermostat.py b/homeassistant/components/climate/generic_thermostat.py index 4b86fa4067bd3..08ac8bf563736 100644 --- a/homeassistant/components/climate/generic_thermostat.py +++ b/homeassistant/components/climate/generic_thermostat.py @@ -20,6 +20,7 @@ from homeassistant.helpers import condition from homeassistant.helpers.event import ( async_track_state_change, async_track_time_interval) +from homeassistant.helpers.restore_state import async_get_last_state import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) @@ -39,7 +40,11 @@ CONF_COLD_TOLERANCE = 'cold_tolerance' CONF_HOT_TOLERANCE = 'hot_tolerance' CONF_KEEP_ALIVE = 'keep_alive' +CONF_PERSISTENCE = 'persistence' +ATTR_NONE = 'none' +ATTR_BOTH = 'both' +ATTR_OPERATION_MODE = 'operation_mode' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HEATER): cv.entity_id, @@ -56,6 +61,8 @@ vol.Optional(CONF_TARGET_TEMP): vol.Coerce(float), vol.Optional(CONF_KEEP_ALIVE): vol.All( cv.time_period, cv.positive_timedelta), + vol.Optional(CONF_PERSISTENCE, default=ATTR_NONE): vol.In( + [ATTR_NONE, ATTR_BOTH, CONF_TARGET_TEMP, ATTR_OPERATION_MODE]), }) @@ -73,11 +80,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) + persistence = config.get(CONF_PERSISTENCE) 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, persistence)]) class GenericThermostat(ClimateDevice): @@ -85,7 +93,7 @@ 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, persistence): """Initialize the thermostat.""" self.hass = hass self._name = name @@ -102,6 +110,7 @@ def __init__(self, hass, name, heater_entity_id, sensor_entity_id, self._min_temp = min_temp self._max_temp = max_temp self._target_temp = target_temp + self._persistence = persistence self._unit = hass.config.units.temperature_unit async_track_state_change( @@ -213,6 +222,19 @@ def _async_sensor_changed(self, entity_id, old_state, new_state): self._async_update_temp(new_state) self._async_control_heating() yield from self.async_update_ha_state() + + @asyncio.coroutine + def async_added_to_hass(self): + """Handle all entity which are about to be added.""" + state = yield from async_get_last_state(self.hass, self.entity_id) + if not state: + return + if self._persistence in [ATTR_BOTH, CONF_TARGET_TEMP]: + self._target_temp=state.attributes[ATTR_TEMPERATURE] + if (self._persistence in [ATTR_BOTH, ATTR_OPERATION_MODE] and + state.attributes[ATTR_OPERATION_MODE] == STATE_OFF): + self.set_operation_mode(STATE_OFF) + return @callback def _async_switch_changed(self, entity_id, old_state, new_state): From 79b90a25fb94eb0940533c19daccaaeb35a4c222 Mon Sep 17 00:00:00 2001 From: ziotibia81 Date: Fri, 17 Nov 2017 14:28:15 +0100 Subject: [PATCH 02/10] Fix code syle --- homeassistant/components/climate/generic_thermostat.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/climate/generic_thermostat.py b/homeassistant/components/climate/generic_thermostat.py index 08ac8bf563736..f9af5899158a6 100644 --- a/homeassistant/components/climate/generic_thermostat.py +++ b/homeassistant/components/climate/generic_thermostat.py @@ -222,7 +222,7 @@ def _async_sensor_changed(self, entity_id, old_state, new_state): self._async_update_temp(new_state) self._async_control_heating() yield from self.async_update_ha_state() - + @asyncio.coroutine def async_added_to_hass(self): """Handle all entity which are about to be added.""" @@ -230,9 +230,9 @@ def async_added_to_hass(self): if not state: return if self._persistence in [ATTR_BOTH, CONF_TARGET_TEMP]: - self._target_temp=state.attributes[ATTR_TEMPERATURE] + self._target_temp = state.attributes[ATTR_TEMPERATURE] if (self._persistence in [ATTR_BOTH, ATTR_OPERATION_MODE] and - state.attributes[ATTR_OPERATION_MODE] == STATE_OFF): + state.attributes[ATTR_OPERATION_MODE] == STATE_OFF): self.set_operation_mode(STATE_OFF) return From 9ff40213f0f5e565506d80ca1dfb9d11442131d0 Mon Sep 17 00:00:00 2001 From: ziotibia81 Date: Fri, 17 Nov 2017 15:09:41 +0100 Subject: [PATCH 03/10] Fix spaces --- homeassistant/components/climate/generic_thermostat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/climate/generic_thermostat.py b/homeassistant/components/climate/generic_thermostat.py index f9af5899158a6..36f47960ea747 100644 --- a/homeassistant/components/climate/generic_thermostat.py +++ b/homeassistant/components/climate/generic_thermostat.py @@ -233,7 +233,7 @@ def async_added_to_hass(self): self._target_temp = state.attributes[ATTR_TEMPERATURE] if (self._persistence in [ATTR_BOTH, ATTR_OPERATION_MODE] and state.attributes[ATTR_OPERATION_MODE] == STATE_OFF): - self.set_operation_mode(STATE_OFF) + self.set_operation_mode(STATE_OFF) return @callback From ad51e4b8134f621a2429fb8ff720629dc1de1d3f Mon Sep 17 00:00:00 2001 From: ziotibia81 Date: Fri, 17 Nov 2017 18:16:51 +0100 Subject: [PATCH 04/10] Fix ATTR_OPERATION_MODE Fix ATTR_OPERATION_MODE from homeassistant.components.climate --- homeassistant/components/climate/generic_thermostat.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/homeassistant/components/climate/generic_thermostat.py b/homeassistant/components/climate/generic_thermostat.py index 36f47960ea747..a491fc3125d01 100644 --- a/homeassistant/components/climate/generic_thermostat.py +++ b/homeassistant/components/climate/generic_thermostat.py @@ -13,7 +13,7 @@ from homeassistant.core import DOMAIN as HA_DOMAIN from homeassistant.components.climate import ( STATE_HEAT, STATE_COOL, STATE_IDLE, ClimateDevice, PLATFORM_SCHEMA, - STATE_AUTO) + STATE_AUTO, ATTR_OPERATION_MODE) 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) @@ -44,7 +44,6 @@ ATTR_NONE = 'none' ATTR_BOTH = 'both' -ATTR_OPERATION_MODE = 'operation_mode' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HEATER): cv.entity_id, From 106c50bf96612ae97a7465ec9337f315f7c54ae1 Mon Sep 17 00:00:00 2001 From: ziotibia81 Date: Fri, 17 Nov 2017 18:59:11 +0100 Subject: [PATCH 05/10] Fix Tests --- .../climate/test_generic_thermostat.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/components/climate/test_generic_thermostat.py b/tests/components/climate/test_generic_thermostat.py index 25887211253bd..4677e7a03c567 100644 --- a/tests/components/climate/test_generic_thermostat.py +++ b/tests/components/climate/test_generic_thermostat.py @@ -892,3 +892,27 @@ def test_custom_setup_params(hass): assert state.attributes.get('min_temp') == MIN_TEMP assert state.attributes.get('max_temp') == MAX_TEMP assert state.attributes.get('temperature') == TARGET_TEMP + + +@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', {'operation_mode': STATE_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, + 'persistence': 'both', + }}) + + state = hass.states.get('climate.test_thermostat') + assert(state.attributes[ATTR_TEMPERATURE] == 20) + assert(state.attributes['operation_mode'] == STATE_OFF) From b9cb47552c78fcc260323791e7fdab66efcad1ed Mon Sep 17 00:00:00 2001 From: ziotibia81 Date: Fri, 17 Nov 2017 19:01:12 +0100 Subject: [PATCH 06/10] More fix to tests --- tests/components/climate/test_generic_thermostat.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/components/climate/test_generic_thermostat.py b/tests/components/climate/test_generic_thermostat.py index 4677e7a03c567..8f2ff220feb08 100644 --- a/tests/components/climate/test_generic_thermostat.py +++ b/tests/components/climate/test_generic_thermostat.py @@ -6,7 +6,7 @@ import pytz import homeassistant.core as ha -from homeassistant.core import callback +from homeassistant.core import callback, CoreState, State from homeassistant.setup import setup_component, async_setup_component from homeassistant.const import ( ATTR_UNIT_OF_MEASUREMENT, @@ -15,14 +15,15 @@ STATE_ON, STATE_OFF, TEMP_CELSIUS, + ATTR_TEMPERATURE ) from homeassistant import loader from homeassistant.util.unit_system import METRIC_SYSTEM from homeassistant.util.async import run_coroutine_threadsafe from homeassistant.components import climate, input_boolean, switch import homeassistant.components as comps -from tests.common import assert_setup_component, get_test_home_assistant - +from tests.common import (assert_setup_component, get_test_home_assistant, + mock_restore_cache) ENTITY = 'climate.test' ENT_SENSOR = 'sensor.test' From 30a11ecd8b9bac0bf04dc74cba18047304186a94 Mon Sep 17 00:00:00 2001 From: ziotibia81 Date: Fri, 17 Nov 2017 19:05:28 +0100 Subject: [PATCH 07/10] Fix conflicts --- tests/components/climate/test_generic_thermostat.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/components/climate/test_generic_thermostat.py b/tests/components/climate/test_generic_thermostat.py index 8f2ff220feb08..18341da6282db 100644 --- a/tests/components/climate/test_generic_thermostat.py +++ b/tests/components/climate/test_generic_thermostat.py @@ -25,6 +25,7 @@ from tests.common import (assert_setup_component, get_test_home_assistant, mock_restore_cache) + ENTITY = 'climate.test' ENT_SENSOR = 'sensor.test' ENT_SWITCH = 'switch.test' @@ -87,7 +88,6 @@ def test_setup_with_sensor(self): class TestGenericThermostatHeaterSwitching(unittest.TestCase): """Test the Generic thermostat heater switching. - Different toggle type devices are tested. """ @@ -334,7 +334,6 @@ def test_invalid_operating_mode(self, log_mock): def test_operating_mode_auto(self): """Test change mode from OFF to AUTO. - Switch turns on when temp below setpoint and mode changes. """ climate.set_operation_mode(self.hass, STATE_OFF) From ef8db94364c00fbd163f064c20752fba5c4a663f Mon Sep 17 00:00:00 2001 From: ziotibia81 Date: Fri, 17 Nov 2017 19:24:02 +0100 Subject: [PATCH 08/10] Fix new line at the end of file --- tests/components/climate/test_generic_thermostat.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/components/climate/test_generic_thermostat.py b/tests/components/climate/test_generic_thermostat.py index 64f92f8978dcb..65a089f45f89a 100644 --- a/tests/components/climate/test_generic_thermostat.py +++ b/tests/components/climate/test_generic_thermostat.py @@ -915,4 +915,5 @@ def test_restore_state(hass): state = hass.states.get('climate.test_thermostat') assert(state.attributes[ATTR_TEMPERATURE] == 20) - assert(state.attributes['operation_mode'] == STATE_OFF) \ No newline at end of file + assert(state.attributes['operation_mode'] == STATE_OFF) + From 56471bd98e58617faefb0acdfd0d044b344d5a92 Mon Sep 17 00:00:00 2001 From: ziotibia81 Date: Fri, 17 Nov 2017 19:25:30 +0100 Subject: [PATCH 09/10] Fix blank space --- tests/components/climate/test_generic_thermostat.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/components/climate/test_generic_thermostat.py b/tests/components/climate/test_generic_thermostat.py index 65a089f45f89a..18341da6282db 100644 --- a/tests/components/climate/test_generic_thermostat.py +++ b/tests/components/climate/test_generic_thermostat.py @@ -916,4 +916,3 @@ def test_restore_state(hass): state = hass.states.get('climate.test_thermostat') assert(state.attributes[ATTR_TEMPERATURE] == 20) assert(state.attributes['operation_mode'] == STATE_OFF) - From 2b9625cc038dce921ae09ea5e6b3c7c04d084ecb Mon Sep 17 00:00:00 2001 From: ziotibia81 Date: Fri, 17 Nov 2017 19:28:45 +0100 Subject: [PATCH 10/10] FIX redefinition of unused 'async_added_to_has --- .../components/climate/generic_thermostat.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/homeassistant/components/climate/generic_thermostat.py b/homeassistant/components/climate/generic_thermostat.py index 83eadcd1cbc8b..f73ae7389d9d9 100644 --- a/homeassistant/components/climate/generic_thermostat.py +++ b/homeassistant/components/climate/generic_thermostat.py @@ -126,17 +126,6 @@ def __init__(self, hass, name, heater_entity_id, sensor_entity_id, if sensor_state: self._async_update_temp(sensor_state) - @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: - self._target_temp = float( - old_state.attributes[ATTR_TEMPERATURE]) - @property def should_poll(self): """Return the polling state."""