Add on/off supported feature to climate (#11379)
* Add on/off supported feature to climate * Lint
This commit is contained in:
parent
ec700c2cd6
commit
eb00e54eba
5 changed files with 125 additions and 17 deletions
|
@ -21,9 +21,9 @@ from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa
|
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID, ATTR_TEMPERATURE, STATE_ON, STATE_OFF, STATE_UNKNOWN,
|
ATTR_ENTITY_ID, ATTR_TEMPERATURE, SERVICE_TURN_ON, SERVICE_TURN_OFF,
|
||||||
TEMP_CELSIUS, PRECISION_WHOLE, PRECISION_TENTHS)
|
STATE_ON, STATE_OFF, STATE_UNKNOWN, TEMP_CELSIUS, PRECISION_WHOLE,
|
||||||
|
PRECISION_TENTHS, )
|
||||||
DOMAIN = 'climate'
|
DOMAIN = 'climate'
|
||||||
|
|
||||||
ENTITY_ID_FORMAT = DOMAIN + '.{}'
|
ENTITY_ID_FORMAT = DOMAIN + '.{}'
|
||||||
|
@ -63,6 +63,7 @@ SUPPORT_HOLD_MODE = 256
|
||||||
SUPPORT_SWING_MODE = 512
|
SUPPORT_SWING_MODE = 512
|
||||||
SUPPORT_AWAY_MODE = 1024
|
SUPPORT_AWAY_MODE = 1024
|
||||||
SUPPORT_AUX_HEAT = 2048
|
SUPPORT_AUX_HEAT = 2048
|
||||||
|
SUPPORT_ON_OFF = 4096
|
||||||
|
|
||||||
ATTR_CURRENT_TEMPERATURE = 'current_temperature'
|
ATTR_CURRENT_TEMPERATURE = 'current_temperature'
|
||||||
ATTR_MAX_TEMP = 'max_temp'
|
ATTR_MAX_TEMP = 'max_temp'
|
||||||
|
@ -92,6 +93,10 @@ CONVERTIBLE_ATTRIBUTE = [
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
ON_OFF_SERVICE_SCHEMA = vol.Schema({
|
||||||
|
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
|
||||||
|
})
|
||||||
|
|
||||||
SET_AWAY_MODE_SCHEMA = vol.Schema({
|
SET_AWAY_MODE_SCHEMA = vol.Schema({
|
||||||
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
|
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
|
||||||
vol.Required(ATTR_AWAY_MODE): cv.boolean,
|
vol.Required(ATTR_AWAY_MODE): cv.boolean,
|
||||||
|
@ -439,6 +444,32 @@ def async_setup(hass, config):
|
||||||
descriptions.get(SERVICE_SET_SWING_MODE),
|
descriptions.get(SERVICE_SET_SWING_MODE),
|
||||||
schema=SET_SWING_MODE_SCHEMA)
|
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
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -449,8 +480,12 @@ class ClimateDevice(Entity):
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Return the current state."""
|
"""Return the current state."""
|
||||||
|
if self.is_on is False:
|
||||||
|
return STATE_OFF
|
||||||
if self.current_operation:
|
if self.current_operation:
|
||||||
return self.current_operation
|
return self.current_operation
|
||||||
|
if self.is_on:
|
||||||
|
return STATE_ON
|
||||||
return STATE_UNKNOWN
|
return STATE_UNKNOWN
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -594,6 +629,11 @@ class ClimateDevice(Entity):
|
||||||
"""Return the current hold mode, e.g., home, away, temp."""
|
"""Return the current hold mode, e.g., home, away, temp."""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self):
|
||||||
|
"""Return true if on."""
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_aux_heat_on(self):
|
def is_aux_heat_on(self):
|
||||||
"""Return true if aux heater."""
|
"""Return true if aux heater."""
|
||||||
|
@ -730,6 +770,28 @@ class ClimateDevice(Entity):
|
||||||
"""
|
"""
|
||||||
return self.hass.async_add_job(self.turn_aux_heat_off)
|
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
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
"""Return the list of supported features."""
|
"""Return the list of supported features."""
|
||||||
|
|
|
@ -9,14 +9,15 @@ from homeassistant.components.climate import (
|
||||||
SUPPORT_TARGET_TEMPERATURE, SUPPORT_TARGET_HUMIDITY,
|
SUPPORT_TARGET_TEMPERATURE, SUPPORT_TARGET_HUMIDITY,
|
||||||
SUPPORT_AWAY_MODE, SUPPORT_HOLD_MODE, SUPPORT_FAN_MODE,
|
SUPPORT_AWAY_MODE, SUPPORT_HOLD_MODE, SUPPORT_FAN_MODE,
|
||||||
SUPPORT_OPERATION_MODE, SUPPORT_AUX_HEAT, SUPPORT_SWING_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
|
from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT, ATTR_TEMPERATURE
|
||||||
|
|
||||||
SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE | SUPPORT_TARGET_HUMIDITY |
|
SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE | SUPPORT_TARGET_HUMIDITY |
|
||||||
SUPPORT_AWAY_MODE | SUPPORT_HOLD_MODE | SUPPORT_FAN_MODE |
|
SUPPORT_AWAY_MODE | SUPPORT_HOLD_MODE | SUPPORT_FAN_MODE |
|
||||||
SUPPORT_OPERATION_MODE | SUPPORT_AUX_HEAT |
|
SUPPORT_OPERATION_MODE | SUPPORT_AUX_HEAT |
|
||||||
SUPPORT_SWING_MODE | SUPPORT_TARGET_TEMPERATURE_HIGH |
|
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):
|
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._swing_list = ['Auto', '1', '2', '3', 'Off']
|
||||||
self._target_temperature_high = target_temp_high
|
self._target_temperature_high = target_temp_high
|
||||||
self._target_temperature_low = target_temp_low
|
self._target_temperature_low = target_temp_low
|
||||||
|
self._on = True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
|
@ -132,6 +134,11 @@ class DemoClimate(ClimateDevice):
|
||||||
"""Return true if aux heat is on."""
|
"""Return true if aux heat is on."""
|
||||||
return self._aux
|
return self._aux
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self):
|
||||||
|
"""Return true if the device is on."""
|
||||||
|
return self._on
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_fan_mode(self):
|
def current_fan_mode(self):
|
||||||
"""Return the fan setting."""
|
"""Return the fan setting."""
|
||||||
|
@ -206,3 +213,13 @@ class DemoClimate(ClimateDevice):
|
||||||
"""Turn auxiliary heater off."""
|
"""Turn auxiliary heater off."""
|
||||||
self._aux = False
|
self._aux = False
|
||||||
self.schedule_update_ha_state()
|
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()
|
||||||
|
|
|
@ -13,13 +13,12 @@ import async_timeout
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_TEMPERATURE, CONF_API_KEY, CONF_ID, STATE_OFF, TEMP_CELSIUS,
|
ATTR_TEMPERATURE, CONF_API_KEY, CONF_ID, TEMP_CELSIUS, TEMP_FAHRENHEIT)
|
||||||
TEMP_FAHRENHEIT)
|
|
||||||
from homeassistant.components.climate import (
|
from homeassistant.components.climate import (
|
||||||
ATTR_CURRENT_HUMIDITY, ClimateDevice, PLATFORM_SCHEMA,
|
ATTR_CURRENT_HUMIDITY, ClimateDevice, PLATFORM_SCHEMA,
|
||||||
SUPPORT_TARGET_TEMPERATURE, SUPPORT_OPERATION_MODE,
|
SUPPORT_TARGET_TEMPERATURE, SUPPORT_OPERATION_MODE,
|
||||||
SUPPORT_FAN_MODE, SUPPORT_SWING_MODE,
|
SUPPORT_FAN_MODE, SUPPORT_SWING_MODE,
|
||||||
SUPPORT_AUX_HEAT)
|
SUPPORT_AUX_HEAT, SUPPORT_ON_OFF)
|
||||||
from homeassistant.exceptions import PlatformNotReady
|
from homeassistant.exceptions import PlatformNotReady
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.helpers import config_validation as cv
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
@ -47,7 +46,7 @@ FIELD_TO_FLAG = {
|
||||||
'mode': SUPPORT_OPERATION_MODE,
|
'mode': SUPPORT_OPERATION_MODE,
|
||||||
'swing': SUPPORT_SWING_MODE,
|
'swing': SUPPORT_SWING_MODE,
|
||||||
'targetTemperature': SUPPORT_TARGET_TEMPERATURE,
|
'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 the list of supported features."""
|
||||||
return self._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):
|
def _do_update(self, data):
|
||||||
self._name = data['room']['name']
|
self._name = data['room']['name']
|
||||||
self._measurements = data['measurements']
|
self._measurements = data['measurements']
|
||||||
|
@ -208,6 +200,8 @@ class SensiboClimate(ClimateDevice):
|
||||||
"""Return true if AC is on."""
|
"""Return true if AC is on."""
|
||||||
return self._ac_states['on']
|
return self._ac_states['on']
|
||||||
|
|
||||||
|
is_on = is_aux_heat_on
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def min_temp(self):
|
def min_temp(self):
|
||||||
"""Return the minimum temperature."""
|
"""Return the minimum temperature."""
|
||||||
|
@ -279,6 +273,9 @@ class SensiboClimate(ClimateDevice):
|
||||||
yield from self._client.async_set_ac_state_property(
|
yield from self._client.async_set_ac_state_property(
|
||||||
self._id, 'on', False)
|
self._id, 'on', False)
|
||||||
|
|
||||||
|
async_on = async_turn_aux_heat_on
|
||||||
|
async_off = async_turn_aux_heat_off
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_update(self):
|
def async_update(self):
|
||||||
"""Retrieve latest state."""
|
"""Retrieve latest state."""
|
||||||
|
|
|
@ -80,7 +80,22 @@ set_swing_mode:
|
||||||
example: 'climate.nest'
|
example: 'climate.nest'
|
||||||
swing_mode:
|
swing_mode:
|
||||||
description: New value of 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:
|
ecobee_set_fan_min_on_time:
|
||||||
description: Set the minimum fan on time.
|
description: Set the minimum fan on time.
|
||||||
fields:
|
fields:
|
||||||
|
|
|
@ -250,3 +250,20 @@ class TestDemoClimate(unittest.TestCase):
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
state = self.hass.states.get(ENTITY_CLIMATE)
|
state = self.hass.states.get(ENTITY_CLIMATE)
|
||||||
self.assertEqual('off', state.attributes.get('aux_heat'))
|
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)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue