From afa4fc4ef59cccc75b40173b811c0f0ebe51111e Mon Sep 17 00:00:00 2001 From: Michael Auchter Date: Sun, 24 Jan 2016 12:02:23 -0600 Subject: [PATCH 1/4] thermostat: split up services --- .../components/thermostat/__init__.py | 83 ++++++++++--------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/homeassistant/components/thermostat/__init__.py b/homeassistant/components/thermostat/__init__.py index 7610070b1f0..dce742b71a8 100644 --- a/homeassistant/components/thermostat/__init__.py +++ b/homeassistant/components/thermostat/__init__.py @@ -75,51 +75,54 @@ def setup(hass, config): SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) - def thermostat_service(service): - """ Handles calls to the services. """ - - # Convert the entity ids to valid light ids - target_thermostats = component.extract_from_service(service) - - if service.service == SERVICE_SET_AWAY_MODE: - away_mode = service.data.get(ATTR_AWAY_MODE) - - if away_mode is None: - _LOGGER.error( - "Received call to %s without attribute %s", - SERVICE_SET_AWAY_MODE, ATTR_AWAY_MODE) - - elif away_mode: - for thermostat in target_thermostats: - thermostat.turn_away_mode_on() - else: - for thermostat in target_thermostats: - thermostat.turn_away_mode_off() - - elif service.service == SERVICE_SET_TEMPERATURE: - temperature = util.convert( - service.data.get(ATTR_TEMPERATURE), float) - - if temperature is None: - return - - for thermostat in target_thermostats: - thermostat.set_temperature(convert( - temperature, hass.config.temperature_unit, - thermostat.unit_of_measurement)) - - for thermostat in target_thermostats: - thermostat.update_ha_state(True) - descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) - hass.services.register( - DOMAIN, SERVICE_SET_AWAY_MODE, thermostat_service, - descriptions.get(SERVICE_SET_AWAY_MODE)) + def away_mode_set_service(service): + """ Set away mode on target thermostats """ + + target_thermostats = component.extract_from_service(service) + + away_mode = service.data.get(ATTR_AWAY_MODE) + + if away_mode is None: + _LOGGER.error( + "Received call to %s without attribute %s", + SERVICE_SET_AWAY_MODE, ATTR_AWAY_MODE) + return + + for thermostat in target_thermostats: + if away_mode: + thermostat.turn_away_mode_on() + else: + thermostat.turn_away_mode_off() + + thermostat.update_ha_state(True) hass.services.register( - DOMAIN, SERVICE_SET_TEMPERATURE, thermostat_service, + DOMAIN, SERVICE_SET_AWAY_MODE, away_mode_set_service, + descriptions.get(SERVICE_SET_AWAY_MODE)) + + def temperature_set_service(service): + """ Set temperature on the target thermostats """ + + target_thermostats = component.extract_from_service(service) + + temperature = util.convert( + service.data.get(ATTR_TEMPERATURE), float) + + if temperature is None: + return + + for thermostat in target_thermostats: + thermostat.set_temperature(convert( + temperature, hass.config.temperature_unit, + thermostat.unit_of_measurement)) + + thermostat.update_ha_state(True) + + hass.services.register( + DOMAIN, SERVICE_SET_TEMPERATURE, temperature_set_service, descriptions.get(SERVICE_SET_TEMPERATURE)) return True From a0ed469aa204aecc60bc61165d78588d82effc3f Mon Sep 17 00:00:00 2001 From: Michael Auchter Date: Mon, 11 Jan 2016 19:08:41 -0600 Subject: [PATCH 2/4] thermostat: move fan attribute up to thermostat --- homeassistant/components/thermostat/__init__.py | 13 +++++++++++++ homeassistant/components/thermostat/nest.py | 6 +++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/thermostat/__init__.py b/homeassistant/components/thermostat/__init__.py index dce742b71a8..17b9a2daca6 100644 --- a/homeassistant/components/thermostat/__init__.py +++ b/homeassistant/components/thermostat/__init__.py @@ -34,6 +34,7 @@ STATE_IDLE = "idle" ATTR_CURRENT_TEMPERATURE = "current_temperature" ATTR_AWAY_MODE = "away_mode" +ATTR_FAN = "fan" ATTR_MAX_TEMP = "max_temp" ATTR_MIN_TEMP = "min_temp" ATTR_TEMPERATURE_LOW = "target_temp_low" @@ -167,6 +168,10 @@ class ThermostatDevice(Entity): if is_away is not None: data[ATTR_AWAY_MODE] = STATE_ON if is_away else STATE_OFF + is_fan_on = self.is_fan_on + if is_fan_on is not None: + data[ATTR_FAN] = STATE_ON if is_fan_on else STATE_OFF + device_attr = self.device_state_attributes if device_attr is not None: @@ -212,6 +217,14 @@ class ThermostatDevice(Entity): """ return None + @property + def is_fan_on(self): + """ + Returns if the fan is on + Return None if not available. + """ + return None + def set_temperate(self, temperature): """ Set new target temperature. """ pass diff --git a/homeassistant/components/thermostat/nest.py b/homeassistant/components/thermostat/nest.py index 423a3195976..88a7761cb28 100644 --- a/homeassistant/components/thermostat/nest.py +++ b/homeassistant/components/thermostat/nest.py @@ -66,7 +66,6 @@ class NestThermostat(ThermostatDevice): return { "humidity": self.device.humidity, "target_humidity": self.device.target_humidity, - "fan": self.device.fan, "mode": self.device.mode } @@ -143,6 +142,11 @@ class NestThermostat(ThermostatDevice): """ Turns away off. """ self.structure.away = False + @property + def is_fan_on(self): + """ Returns whether the fan is on """ + return self.device.fan + @property def min_temp(self): """ Identifies min_temp in Nest API or defaults if not available. """ From df94c909f7db9c7948dc097ad0ee52169cb41bbb Mon Sep 17 00:00:00 2001 From: Michael Auchter Date: Mon, 11 Jan 2016 19:23:24 -0600 Subject: [PATCH 3/4] thermostat: add service to control fan mode --- .../components/thermostat/__init__.py | 47 +++++++++++++++++++ .../components/thermostat/services.yaml | 12 +++++ 2 files changed, 59 insertions(+) diff --git a/homeassistant/components/thermostat/__init__.py b/homeassistant/components/thermostat/__init__.py index 17b9a2daca6..d92a71ba1f6 100644 --- a/homeassistant/components/thermostat/__init__.py +++ b/homeassistant/components/thermostat/__init__.py @@ -27,6 +27,7 @@ SCAN_INTERVAL = 60 SERVICE_SET_AWAY_MODE = "set_away_mode" SERVICE_SET_TEMPERATURE = "set_temperature" +SERVICE_SET_FAN_MODE = "set_fan_mode" STATE_HEAT = "heat" STATE_COOL = "cool" @@ -70,6 +71,19 @@ def set_temperature(hass, temperature, entity_id=None): hass.services.call(DOMAIN, SERVICE_SET_TEMPERATURE, data) +def set_fan_mode(hass, fan_mode, entity_id=None): + """ Turn all or specified thermostat fan mode on. """ + data = { + ATTR_FAN: fan_mode + } + + if entity_id: + data[ATTR_ENTITY_ID] = entity_id + + hass.services.call(DOMAIN, SERVICE_SET_FAN_MODE, data) + + +# pylint: disable=too-many-branches def setup(hass, config): """ Setup thermostats. """ component = EntityComponent(_LOGGER, DOMAIN, hass, @@ -126,6 +140,31 @@ def setup(hass, config): DOMAIN, SERVICE_SET_TEMPERATURE, temperature_set_service, descriptions.get(SERVICE_SET_TEMPERATURE)) + def fan_mode_set_service(service): + """ Set fan mode on target thermostats """ + + target_thermostats = component.extract_from_service(service) + + fan_mode = service.data.get(ATTR_FAN) + + if fan_mode is None: + _LOGGER.error( + "Received call to %s without attribute %s", + SERVICE_SET_FAN_MODE, ATTR_FAN) + return + + for thermostat in target_thermostats: + if fan_mode: + thermostat.turn_fan_on() + else: + thermostat.turn_fan_off() + + thermostat.update_ha_state(True) + + hass.services.register( + DOMAIN, SERVICE_SET_FAN_MODE, fan_mode_set_service, + descriptions.get(SERVICE_SET_FAN_MODE)) + return True @@ -237,6 +276,14 @@ class ThermostatDevice(Entity): """ Turns away mode off. """ pass + def turn_fan_on(self): + """ Turns fan on. """ + pass + + def turn_fan_off(self): + """ Turns fan off. """ + pass + @property def min_temp(self): """ Return minimum temperature. """ diff --git a/homeassistant/components/thermostat/services.yaml b/homeassistant/components/thermostat/services.yaml index 0d4f4726204..3592dfce75d 100644 --- a/homeassistant/components/thermostat/services.yaml +++ b/homeassistant/components/thermostat/services.yaml @@ -22,3 +22,15 @@ set_temperature: temperature: description: New target temperature for thermostat example: 25 + +set_fan_mode: + description: Turn fan on/off for a thermostat + + fields: + entity_id: + description: Name(s) of entities to change + example: 'thermostat.nest' + + fan: + description: New value of fan mode + example: true From 881c82c2df42628413c7a55825e5d79d726fe879 Mon Sep 17 00:00:00 2001 From: Michael Auchter Date: Mon, 11 Jan 2016 19:24:27 -0600 Subject: [PATCH 4/4] nest: implement fan control --- homeassistant/components/thermostat/nest.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/homeassistant/components/thermostat/nest.py b/homeassistant/components/thermostat/nest.py index 88a7761cb28..e0e1f74cdbc 100644 --- a/homeassistant/components/thermostat/nest.py +++ b/homeassistant/components/thermostat/nest.py @@ -147,6 +147,14 @@ class NestThermostat(ThermostatDevice): """ Returns whether the fan is on """ return self.device.fan + def turn_fan_on(self): + """ Turns fan on """ + self.device.fan = True + + def turn_fan_off(self): + """ Turns fan off """ + self.device.fan = False + @property def min_temp(self): """ Identifies min_temp in Nest API or defaults if not available. """