Add on/off supported feature to climate (#11379)

* Add on/off supported feature to climate

* Lint
This commit is contained in:
Andrey 2018-01-04 00:10:54 +02:00 committed by Lukas Barth
parent ec700c2cd6
commit eb00e54eba
5 changed files with 125 additions and 17 deletions

View file

@ -21,9 +21,9 @@ from homeassistant.helpers.entity import Entity
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa
import homeassistant.helpers.config_validation as cv
from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_TEMPERATURE, STATE_ON, STATE_OFF, STATE_UNKNOWN,
TEMP_CELSIUS, PRECISION_WHOLE, PRECISION_TENTHS)
ATTR_ENTITY_ID, ATTR_TEMPERATURE, SERVICE_TURN_ON, SERVICE_TURN_OFF,
STATE_ON, STATE_OFF, STATE_UNKNOWN, TEMP_CELSIUS, PRECISION_WHOLE,
PRECISION_TENTHS, )
DOMAIN = 'climate'
ENTITY_ID_FORMAT = DOMAIN + '.{}'
@ -63,6 +63,7 @@ SUPPORT_HOLD_MODE = 256
SUPPORT_SWING_MODE = 512
SUPPORT_AWAY_MODE = 1024
SUPPORT_AUX_HEAT = 2048
SUPPORT_ON_OFF = 4096
ATTR_CURRENT_TEMPERATURE = 'current_temperature'
ATTR_MAX_TEMP = 'max_temp'
@ -92,6 +93,10 @@ CONVERTIBLE_ATTRIBUTE = [
_LOGGER = logging.getLogger(__name__)
ON_OFF_SERVICE_SCHEMA = vol.Schema({
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
})
SET_AWAY_MODE_SCHEMA = vol.Schema({
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
vol.Required(ATTR_AWAY_MODE): cv.boolean,
@ -439,6 +444,32 @@ def async_setup(hass, config):
descriptions.get(SERVICE_SET_SWING_MODE),
schema=SET_SWING_MODE_SCHEMA)
@asyncio.coroutine
def async_on_off_service(service):
"""Handle on/off calls."""
target_climate = component.async_extract_from_service(service)
update_tasks = []
for climate in target_climate:
if service.service == SERVICE_TURN_ON:
yield from climate.async_turn_on()
elif service.service == SERVICE_TURN_OFF:
yield from climate.async_turn_off()
if not climate.should_poll:
continue
update_tasks.append(climate.async_update_ha_state(True))
if update_tasks:
yield from asyncio.wait(update_tasks, loop=hass.loop)
hass.services.async_register(
DOMAIN, SERVICE_TURN_OFF, async_on_off_service,
descriptions.get(SERVICE_TURN_OFF), schema=ON_OFF_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_TURN_ON, async_on_off_service,
descriptions.get(SERVICE_TURN_ON), schema=ON_OFF_SERVICE_SCHEMA)
return True
@ -449,8 +480,12 @@ class ClimateDevice(Entity):
@property
def state(self):
"""Return the current state."""
if self.is_on is False:
return STATE_OFF
if self.current_operation:
return self.current_operation
if self.is_on:
return STATE_ON
return STATE_UNKNOWN
@property
@ -594,6 +629,11 @@ class ClimateDevice(Entity):
"""Return the current hold mode, e.g., home, away, temp."""
return None
@property
def is_on(self):
"""Return true if on."""
return None
@property
def is_aux_heat_on(self):
"""Return true if aux heater."""
@ -730,6 +770,28 @@ class ClimateDevice(Entity):
"""
return self.hass.async_add_job(self.turn_aux_heat_off)
def turn_on(self):
"""Turn device on."""
raise NotImplementedError()
def async_turn_on(self):
"""Turn device on.
This method must be run in the event loop and returns a coroutine.
"""
return self.hass.async_add_job(self.turn_on)
def turn_off(self):
"""Turn device off."""
raise NotImplementedError()
def async_turn_off(self):
"""Turn device off.
This method must be run in the event loop and returns a coroutine.
"""
return self.hass.async_add_job(self.turn_off)
@property
def supported_features(self):
"""Return the list of supported features."""

View file

@ -9,14 +9,15 @@ from homeassistant.components.climate import (
SUPPORT_TARGET_TEMPERATURE, SUPPORT_TARGET_HUMIDITY,
SUPPORT_AWAY_MODE, SUPPORT_HOLD_MODE, SUPPORT_FAN_MODE,
SUPPORT_OPERATION_MODE, SUPPORT_AUX_HEAT, SUPPORT_SWING_MODE,
SUPPORT_TARGET_TEMPERATURE_HIGH, SUPPORT_TARGET_TEMPERATURE_LOW)
SUPPORT_TARGET_TEMPERATURE_HIGH, SUPPORT_TARGET_TEMPERATURE_LOW,
SUPPORT_ON_OFF)
from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT, ATTR_TEMPERATURE
SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE | SUPPORT_TARGET_HUMIDITY |
SUPPORT_AWAY_MODE | SUPPORT_HOLD_MODE | SUPPORT_FAN_MODE |
SUPPORT_OPERATION_MODE | SUPPORT_AUX_HEAT |
SUPPORT_SWING_MODE | SUPPORT_TARGET_TEMPERATURE_HIGH |
SUPPORT_TARGET_TEMPERATURE_LOW)
SUPPORT_TARGET_TEMPERATURE_LOW, SUPPORT_ON_OFF)
def setup_platform(hass, config, add_devices, discovery_info=None):
@ -56,6 +57,7 @@ class DemoClimate(ClimateDevice):
self._swing_list = ['Auto', '1', '2', '3', 'Off']
self._target_temperature_high = target_temp_high
self._target_temperature_low = target_temp_low
self._on = True
@property
def supported_features(self):
@ -132,6 +134,11 @@ class DemoClimate(ClimateDevice):
"""Return true if aux heat is on."""
return self._aux
@property
def is_on(self):
"""Return true if the device is on."""
return self._on
@property
def current_fan_mode(self):
"""Return the fan setting."""
@ -206,3 +213,13 @@ class DemoClimate(ClimateDevice):
"""Turn auxiliary heater off."""
self._aux = False
self.schedule_update_ha_state()
def turn_on(self):
"""Turn on."""
self._on = True
self.schedule_update_ha_state()
def turn_off(self):
"""Turn off."""
self._on = False
self.schedule_update_ha_state()

View file

@ -13,13 +13,12 @@ import async_timeout
import voluptuous as vol
from homeassistant.const import (
ATTR_TEMPERATURE, CONF_API_KEY, CONF_ID, STATE_OFF, TEMP_CELSIUS,
TEMP_FAHRENHEIT)
ATTR_TEMPERATURE, CONF_API_KEY, CONF_ID, TEMP_CELSIUS, TEMP_FAHRENHEIT)
from homeassistant.components.climate import (
ATTR_CURRENT_HUMIDITY, ClimateDevice, PLATFORM_SCHEMA,
SUPPORT_TARGET_TEMPERATURE, SUPPORT_OPERATION_MODE,
SUPPORT_FAN_MODE, SUPPORT_SWING_MODE,
SUPPORT_AUX_HEAT)
SUPPORT_AUX_HEAT, SUPPORT_ON_OFF)
from homeassistant.exceptions import PlatformNotReady
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession
@ -47,7 +46,7 @@ FIELD_TO_FLAG = {
'mode': SUPPORT_OPERATION_MODE,
'swing': SUPPORT_SWING_MODE,
'targetTemperature': SUPPORT_TARGET_TEMPERATURE,
'on': SUPPORT_AUX_HEAT,
'on': SUPPORT_AUX_HEAT | SUPPORT_ON_OFF,
}
@ -92,13 +91,6 @@ class SensiboClimate(ClimateDevice):
"""Return the list of supported features."""
return self._supported_features
@property
def state(self):
"""Return the current state."""
if not self.is_aux_heat_on:
return STATE_OFF
return super().state
def _do_update(self, data):
self._name = data['room']['name']
self._measurements = data['measurements']
@ -208,6 +200,8 @@ class SensiboClimate(ClimateDevice):
"""Return true if AC is on."""
return self._ac_states['on']
is_on = is_aux_heat_on
@property
def min_temp(self):
"""Return the minimum temperature."""
@ -279,6 +273,9 @@ class SensiboClimate(ClimateDevice):
yield from self._client.async_set_ac_state_property(
self._id, 'on', False)
async_on = async_turn_aux_heat_on
async_off = async_turn_aux_heat_off
@asyncio.coroutine
def async_update(self):
"""Retrieve latest state."""

View file

@ -80,7 +80,22 @@ set_swing_mode:
example: 'climate.nest'
swing_mode:
description: New value of swing mode.
example: 1
example:
turn_on:
description: Turn climate device on.
fields:
entity_id:
description: Name(s) of entities to change.
example: 'climate.kitchen'
turn_off:
description: Turn climate device off.
fields:
entity_id:
description: Name(s) of entities to change.
example: 'climate.kitchen'
ecobee_set_fan_min_on_time:
description: Set the minimum fan on time.
fields:

View file

@ -250,3 +250,20 @@ class TestDemoClimate(unittest.TestCase):
self.hass.block_till_done()
state = self.hass.states.get(ENTITY_CLIMATE)
self.assertEqual('off', state.attributes.get('aux_heat'))
def test_set_on_off(self):
"""Test on/off service."""
state = self.hass.states.get(ENTITY_ECOBEE)
self.assertEqual('auto', state.state)
self.hass.services.call(climate.DOMAIN, climate.SERVICE_TURN_OFF,
{climate.ATTR_ENTITY_ID: ENTITY_ECOBEE})
self.hass.block_till_done()
state = self.hass.states.get(ENTITY_ECOBEE)
self.assertEqual('off', state.state)
self.hass.services.call(climate.DOMAIN, climate.SERVICE_TURN_ON,
{climate.ATTR_ENTITY_ID: ENTITY_ECOBEE})
self.hass.block_till_done()
state = self.hass.states.get(ENTITY_ECOBEE)
self.assertEqual('auto', state.state)