Google Assistant: Add support for open/close binary sensors (#22674)
* Google Assistant: Add support for binary sensors * Update test
This commit is contained in:
parent
3872ac9bf9
commit
14da2fd8c9
4 changed files with 207 additions and 73 deletions
|
@ -15,30 +15,100 @@ DOMAIN = 'binary_sensor'
|
|||
SCAN_INTERVAL = timedelta(seconds=30)
|
||||
|
||||
ENTITY_ID_FORMAT = DOMAIN + '.{}'
|
||||
|
||||
# On means low, Off means normal
|
||||
DEVICE_CLASS_BATTERY = 'battery'
|
||||
|
||||
# On means cold, Off means normal
|
||||
DEVICE_CLASS_COLD = 'cold'
|
||||
|
||||
# On means connected, Off means disconnected
|
||||
DEVICE_CLASS_CONNECTIVITY = 'connectivity'
|
||||
|
||||
# On means open, Off means closed
|
||||
DEVICE_CLASS_DOOR = 'door'
|
||||
|
||||
# On means open, Off means closed
|
||||
DEVICE_CLASS_GARAGE_DOOR = 'garage_door'
|
||||
|
||||
# On means gas detected, Off means no gas (clear)
|
||||
DEVICE_CLASS_GAS = 'gas'
|
||||
|
||||
# On means hot, Off means normal
|
||||
DEVICE_CLASS_HEAT = 'heat'
|
||||
|
||||
# On means light detected, Off means no light
|
||||
DEVICE_CLASS_LIGHT = 'light'
|
||||
|
||||
# On means open (unlocked), Off means closed (locked)
|
||||
DEVICE_CLASS_LOCK = 'lock'
|
||||
|
||||
# On means wet, Off means dry
|
||||
DEVICE_CLASS_MOISTURE = 'moisture'
|
||||
|
||||
# On means motion detected, Off means no motion (clear)
|
||||
DEVICE_CLASS_MOTION = 'motion'
|
||||
|
||||
# On means moving, Off means not moving (stopped)
|
||||
DEVICE_CLASS_MOVING = 'moving'
|
||||
|
||||
# On means occupied, Off means not occupied (clear)
|
||||
DEVICE_CLASS_OCCUPANCY = 'occupancy'
|
||||
|
||||
# On means open, Off means closed
|
||||
DEVICE_CLASS_OPENING = 'opening'
|
||||
|
||||
# On means plugged in, Off means unplugged
|
||||
DEVICE_CLASS_PLUG = 'plug'
|
||||
|
||||
# On means power detected, Off means no power
|
||||
DEVICE_CLASS_POWER = 'power'
|
||||
|
||||
# On means home, Off means away
|
||||
DEVICE_CLASS_PRESENCE = 'presence'
|
||||
|
||||
# On means problem detected, Off means no problem (OK)
|
||||
DEVICE_CLASS_PROBLEM = 'problem'
|
||||
|
||||
# On means unsafe, Off means safe
|
||||
DEVICE_CLASS_SAFETY = 'safety'
|
||||
|
||||
# On means smoke detected, Off means no smoke (clear)
|
||||
DEVICE_CLASS_SMOKE = 'smoke'
|
||||
|
||||
# On means sound detected, Off means no sound (clear)
|
||||
DEVICE_CLASS_SOUND = 'sound'
|
||||
|
||||
# On means vibration detected, Off means no vibration
|
||||
DEVICE_CLASS_VIBRATION = 'vibration'
|
||||
|
||||
# On means open, Off means closed
|
||||
DEVICE_CLASS_WINDOW = 'window'
|
||||
|
||||
DEVICE_CLASSES = [
|
||||
'battery', # On means low, Off means normal
|
||||
'cold', # On means cold, Off means normal
|
||||
'connectivity', # On means connected, Off means disconnected
|
||||
'door', # On means open, Off means closed
|
||||
'garage_door', # On means open, Off means closed
|
||||
'gas', # On means gas detected, Off means no gas (clear)
|
||||
'heat', # On means hot, Off means normal
|
||||
'light', # On means light detected, Off means no light
|
||||
'lock', # On means open (unlocked), Off means closed (locked)
|
||||
'moisture', # On means wet, Off means dry
|
||||
'motion', # On means motion detected, Off means no motion (clear)
|
||||
'moving', # On means moving, Off means not moving (stopped)
|
||||
'occupancy', # On means occupied, Off means not occupied (clear)
|
||||
'opening', # On means open, Off means closed
|
||||
'plug', # On means plugged in, Off means unplugged
|
||||
'power', # On means power detected, Off means no power
|
||||
'presence', # On means home, Off means away
|
||||
'problem', # On means problem detected, Off means no problem (OK)
|
||||
'safety', # On means unsafe, Off means safe
|
||||
'smoke', # On means smoke detected, Off means no smoke (clear)
|
||||
'sound', # On means sound detected, Off means no sound (clear)
|
||||
'vibration', # On means vibration detected, Off means no vibration
|
||||
'window', # On means open, Off means closed
|
||||
DEVICE_CLASS_BATTERY,
|
||||
DEVICE_CLASS_COLD,
|
||||
DEVICE_CLASS_CONNECTIVITY,
|
||||
DEVICE_CLASS_DOOR,
|
||||
DEVICE_CLASS_GARAGE_DOOR,
|
||||
DEVICE_CLASS_GAS,
|
||||
DEVICE_CLASS_HEAT,
|
||||
DEVICE_CLASS_LIGHT,
|
||||
DEVICE_CLASS_LOCK,
|
||||
DEVICE_CLASS_MOISTURE,
|
||||
DEVICE_CLASS_MOTION,
|
||||
DEVICE_CLASS_MOVING,
|
||||
DEVICE_CLASS_OCCUPANCY,
|
||||
DEVICE_CLASS_OPENING,
|
||||
DEVICE_CLASS_PLUG,
|
||||
DEVICE_CLASS_POWER,
|
||||
DEVICE_CLASS_PRESENCE,
|
||||
DEVICE_CLASS_PROBLEM,
|
||||
DEVICE_CLASS_SAFETY,
|
||||
DEVICE_CLASS_SMOKE,
|
||||
DEVICE_CLASS_SOUND,
|
||||
DEVICE_CLASS_VIBRATION,
|
||||
DEVICE_CLASS_WINDOW,
|
||||
]
|
||||
|
||||
DEVICE_CLASSES_SCHEMA = vol.All(vol.Lower, vol.In(DEVICE_CLASSES))
|
||||
|
|
|
@ -9,7 +9,7 @@ from homeassistant.util.decorator import Registry
|
|||
from homeassistant.core import callback
|
||||
from homeassistant.const import (
|
||||
CLOUD_NEVER_EXPOSED_ENTITIES, CONF_NAME, STATE_UNAVAILABLE,
|
||||
ATTR_SUPPORTED_FEATURES, ATTR_ENTITY_ID,
|
||||
ATTR_SUPPORTED_FEATURES, ATTR_ENTITY_ID, ATTR_DEVICE_CLASS,
|
||||
)
|
||||
from homeassistant.components import (
|
||||
camera,
|
||||
|
@ -92,10 +92,11 @@ class _GoogleEntity:
|
|||
state = self.state
|
||||
domain = state.domain
|
||||
features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
||||
device_class = state.attributes.get(ATTR_DEVICE_CLASS)
|
||||
|
||||
self._traits = [Trait(self.hass, state, self.config)
|
||||
for Trait in trait.TRAITS
|
||||
if Trait.supported(domain, features)]
|
||||
if Trait.supported(domain, features, device_class)]
|
||||
return self._traits
|
||||
|
||||
async def sync_serialize(self):
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import logging
|
||||
|
||||
from homeassistant.components import (
|
||||
binary_sensor,
|
||||
camera,
|
||||
cover,
|
||||
group,
|
||||
|
@ -127,7 +128,7 @@ class BrightnessTrait(_Trait):
|
|||
]
|
||||
|
||||
@staticmethod
|
||||
def supported(domain, features):
|
||||
def supported(domain, features, device_class):
|
||||
"""Test if state is supported."""
|
||||
if domain == light.DOMAIN:
|
||||
return features & light.SUPPORT_BRIGHTNESS
|
||||
|
@ -193,7 +194,7 @@ class CameraStreamTrait(_Trait):
|
|||
stream_info = None
|
||||
|
||||
@staticmethod
|
||||
def supported(domain, features):
|
||||
def supported(domain, features, device_class):
|
||||
"""Test if state is supported."""
|
||||
if domain == camera.DOMAIN:
|
||||
return features & camera.SUPPORT_STREAM
|
||||
|
@ -236,7 +237,7 @@ class OnOffTrait(_Trait):
|
|||
]
|
||||
|
||||
@staticmethod
|
||||
def supported(domain, features):
|
||||
def supported(domain, features, device_class):
|
||||
"""Test if state is supported."""
|
||||
return domain in (
|
||||
group.DOMAIN,
|
||||
|
@ -285,7 +286,7 @@ class ColorSpectrumTrait(_Trait):
|
|||
]
|
||||
|
||||
@staticmethod
|
||||
def supported(domain, features):
|
||||
def supported(domain, features, device_class):
|
||||
"""Test if state is supported."""
|
||||
if domain != light.DOMAIN:
|
||||
return False
|
||||
|
@ -341,7 +342,7 @@ class ColorTemperatureTrait(_Trait):
|
|||
]
|
||||
|
||||
@staticmethod
|
||||
def supported(domain, features):
|
||||
def supported(domain, features, device_class):
|
||||
"""Test if state is supported."""
|
||||
if domain != light.DOMAIN:
|
||||
return False
|
||||
|
@ -414,7 +415,7 @@ class SceneTrait(_Trait):
|
|||
]
|
||||
|
||||
@staticmethod
|
||||
def supported(domain, features):
|
||||
def supported(domain, features, device_class):
|
||||
"""Test if state is supported."""
|
||||
return domain in (scene.DOMAIN, script.DOMAIN)
|
||||
|
||||
|
@ -450,7 +451,7 @@ class DockTrait(_Trait):
|
|||
]
|
||||
|
||||
@staticmethod
|
||||
def supported(domain, features):
|
||||
def supported(domain, features, device_class):
|
||||
"""Test if state is supported."""
|
||||
return domain == vacuum.DOMAIN
|
||||
|
||||
|
@ -484,7 +485,7 @@ class StartStopTrait(_Trait):
|
|||
]
|
||||
|
||||
@staticmethod
|
||||
def supported(domain, features):
|
||||
def supported(domain, features, device_class):
|
||||
"""Test if state is supported."""
|
||||
return domain == vacuum.DOMAIN
|
||||
|
||||
|
@ -554,7 +555,7 @@ class TemperatureSettingTrait(_Trait):
|
|||
google_to_hass = {value: key for key, value in hass_to_google.items()}
|
||||
|
||||
@staticmethod
|
||||
def supported(domain, features):
|
||||
def supported(domain, features, device_class):
|
||||
"""Test if state is supported."""
|
||||
if domain != climate.DOMAIN:
|
||||
return False
|
||||
|
@ -739,7 +740,7 @@ class LockUnlockTrait(_Trait):
|
|||
]
|
||||
|
||||
@staticmethod
|
||||
def supported(domain, features):
|
||||
def supported(domain, features, device_class):
|
||||
"""Test if state is supported."""
|
||||
return domain == lock.DOMAIN
|
||||
|
||||
|
@ -790,7 +791,7 @@ class FanSpeedTrait(_Trait):
|
|||
}
|
||||
|
||||
@staticmethod
|
||||
def supported(domain, features):
|
||||
def supported(domain, features, device_class):
|
||||
"""Test if state is supported."""
|
||||
if domain != fan.DOMAIN:
|
||||
return False
|
||||
|
@ -941,7 +942,7 @@ class ModesTrait(_Trait):
|
|||
}
|
||||
|
||||
@staticmethod
|
||||
def supported(domain, features):
|
||||
def supported(domain, features, device_class):
|
||||
"""Test if state is supported."""
|
||||
if domain != media_player.DOMAIN:
|
||||
return False
|
||||
|
@ -1042,13 +1043,25 @@ class OpenCloseTrait(_Trait):
|
|||
]
|
||||
|
||||
@staticmethod
|
||||
def supported(domain, features):
|
||||
def supported(domain, features, device_class):
|
||||
"""Test if state is supported."""
|
||||
return domain == cover.DOMAIN
|
||||
if domain == cover.DOMAIN:
|
||||
return True
|
||||
|
||||
return domain == binary_sensor.DOMAIN and device_class in (
|
||||
binary_sensor.DEVICE_CLASS_DOOR,
|
||||
binary_sensor.DEVICE_CLASS_GARAGE_DOOR,
|
||||
binary_sensor.DEVICE_CLASS_LOCK,
|
||||
binary_sensor.DEVICE_CLASS_OPENING,
|
||||
binary_sensor.DEVICE_CLASS_WINDOW,
|
||||
)
|
||||
|
||||
def sync_attributes(self):
|
||||
"""Return opening direction."""
|
||||
return {}
|
||||
attrs = {}
|
||||
if self.state.domain == binary_sensor.DOMAIN:
|
||||
attrs['queryOnlyOpenClose'] = True
|
||||
return attrs
|
||||
|
||||
def query_attributes(self):
|
||||
"""Return state query attributes."""
|
||||
|
@ -1073,6 +1086,12 @@ class OpenCloseTrait(_Trait):
|
|||
else:
|
||||
response['openPercent'] = 0
|
||||
|
||||
elif domain == binary_sensor.DOMAIN:
|
||||
if self.state.state == STATE_ON:
|
||||
response['openPercent'] = 100
|
||||
else:
|
||||
response['openPercent'] = 0
|
||||
|
||||
return response
|
||||
|
||||
async def execute(self, command, data, params):
|
||||
|
|
|
@ -4,6 +4,7 @@ from unittest.mock import patch, Mock
|
|||
import pytest
|
||||
|
||||
from homeassistant.components import (
|
||||
binary_sensor,
|
||||
camera,
|
||||
cover,
|
||||
fan,
|
||||
|
@ -22,7 +23,7 @@ from homeassistant.components.google_assistant import trait, helpers, const
|
|||
from homeassistant.const import (
|
||||
STATE_ON, STATE_OFF, ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF,
|
||||
TEMP_CELSIUS, TEMP_FAHRENHEIT, ATTR_SUPPORTED_FEATURES, ATTR_TEMPERATURE,
|
||||
ATTR_ASSUMED_STATE)
|
||||
ATTR_DEVICE_CLASS, ATTR_ASSUMED_STATE)
|
||||
from homeassistant.core import State, DOMAIN as HA_DOMAIN, EVENT_CALL_SERVICE
|
||||
from homeassistant.util import color
|
||||
from tests.common import async_mock_service, mock_coro
|
||||
|
@ -49,7 +50,7 @@ UNSAFE_CONFIG = helpers.Config(
|
|||
async def test_brightness_light(hass):
|
||||
"""Test brightness trait support for light domain."""
|
||||
assert trait.BrightnessTrait.supported(light.DOMAIN,
|
||||
light.SUPPORT_BRIGHTNESS)
|
||||
light.SUPPORT_BRIGHTNESS, None)
|
||||
|
||||
trt = trait.BrightnessTrait(hass, State('light.bla', light.STATE_ON, {
|
||||
light.ATTR_BRIGHTNESS: 243
|
||||
|
@ -87,7 +88,8 @@ async def test_brightness_light(hass):
|
|||
async def test_brightness_media_player(hass):
|
||||
"""Test brightness trait support for media player domain."""
|
||||
assert trait.BrightnessTrait.supported(media_player.DOMAIN,
|
||||
media_player.SUPPORT_VOLUME_SET)
|
||||
media_player.SUPPORT_VOLUME_SET,
|
||||
None)
|
||||
|
||||
trt = trait.BrightnessTrait(hass, State(
|
||||
'media_player.bla', media_player.STATE_PLAYING, {
|
||||
|
@ -116,7 +118,7 @@ async def test_camera_stream(hass):
|
|||
"""Test camera stream trait support for camera domain."""
|
||||
hass.config.api = Mock(base_url='http://1.1.1.1:8123')
|
||||
assert trait.CameraStreamTrait.supported(camera.DOMAIN,
|
||||
camera.SUPPORT_STREAM)
|
||||
camera.SUPPORT_STREAM, None)
|
||||
|
||||
trt = trait.CameraStreamTrait(
|
||||
hass, State('camera.bla', camera.STATE_IDLE, {}), BASIC_CONFIG
|
||||
|
@ -143,7 +145,7 @@ async def test_camera_stream(hass):
|
|||
|
||||
async def test_onoff_group(hass):
|
||||
"""Test OnOff trait support for group domain."""
|
||||
assert trait.OnOffTrait.supported(group.DOMAIN, 0)
|
||||
assert trait.OnOffTrait.supported(group.DOMAIN, 0, None)
|
||||
|
||||
trt_on = trait.OnOffTrait(hass, State('group.bla', STATE_ON), BASIC_CONFIG)
|
||||
|
||||
|
@ -181,7 +183,7 @@ async def test_onoff_group(hass):
|
|||
|
||||
async def test_onoff_input_boolean(hass):
|
||||
"""Test OnOff trait support for input_boolean domain."""
|
||||
assert trait.OnOffTrait.supported(input_boolean.DOMAIN, 0)
|
||||
assert trait.OnOffTrait.supported(input_boolean.DOMAIN, 0, None)
|
||||
|
||||
trt_on = trait.OnOffTrait(hass, State('input_boolean.bla', STATE_ON),
|
||||
BASIC_CONFIG)
|
||||
|
@ -221,7 +223,7 @@ async def test_onoff_input_boolean(hass):
|
|||
|
||||
async def test_onoff_switch(hass):
|
||||
"""Test OnOff trait support for switch domain."""
|
||||
assert trait.OnOffTrait.supported(switch.DOMAIN, 0)
|
||||
assert trait.OnOffTrait.supported(switch.DOMAIN, 0, None)
|
||||
|
||||
trt_on = trait.OnOffTrait(hass, State('switch.bla', STATE_ON),
|
||||
BASIC_CONFIG)
|
||||
|
@ -260,7 +262,7 @@ async def test_onoff_switch(hass):
|
|||
|
||||
async def test_onoff_fan(hass):
|
||||
"""Test OnOff trait support for fan domain."""
|
||||
assert trait.OnOffTrait.supported(fan.DOMAIN, 0)
|
||||
assert trait.OnOffTrait.supported(fan.DOMAIN, 0, None)
|
||||
|
||||
trt_on = trait.OnOffTrait(hass, State('fan.bla', STATE_ON), BASIC_CONFIG)
|
||||
|
||||
|
@ -296,7 +298,7 @@ async def test_onoff_fan(hass):
|
|||
|
||||
async def test_onoff_light(hass):
|
||||
"""Test OnOff trait support for light domain."""
|
||||
assert trait.OnOffTrait.supported(light.DOMAIN, 0)
|
||||
assert trait.OnOffTrait.supported(light.DOMAIN, 0, None)
|
||||
|
||||
trt_on = trait.OnOffTrait(hass, State('light.bla', STATE_ON), BASIC_CONFIG)
|
||||
|
||||
|
@ -334,7 +336,7 @@ async def test_onoff_light(hass):
|
|||
|
||||
async def test_onoff_media_player(hass):
|
||||
"""Test OnOff trait support for media_player domain."""
|
||||
assert trait.OnOffTrait.supported(media_player.DOMAIN, 0)
|
||||
assert trait.OnOffTrait.supported(media_player.DOMAIN, 0, None)
|
||||
|
||||
trt_on = trait.OnOffTrait(hass, State('media_player.bla', STATE_ON),
|
||||
BASIC_CONFIG)
|
||||
|
@ -376,12 +378,12 @@ async def test_onoff_media_player(hass):
|
|||
async def test_onoff_climate(hass):
|
||||
"""Test OnOff trait not supported for climate domain."""
|
||||
assert not trait.OnOffTrait.supported(
|
||||
climate.DOMAIN, climate.SUPPORT_ON_OFF)
|
||||
climate.DOMAIN, climate.SUPPORT_ON_OFF, None)
|
||||
|
||||
|
||||
async def test_dock_vacuum(hass):
|
||||
"""Test dock trait support for vacuum domain."""
|
||||
assert trait.DockTrait.supported(vacuum.DOMAIN, 0)
|
||||
assert trait.DockTrait.supported(vacuum.DOMAIN, 0, None)
|
||||
|
||||
trt = trait.DockTrait(hass, State('vacuum.bla', vacuum.STATE_IDLE),
|
||||
BASIC_CONFIG)
|
||||
|
@ -404,7 +406,7 @@ async def test_dock_vacuum(hass):
|
|||
|
||||
async def test_startstop_vacuum(hass):
|
||||
"""Test startStop trait support for vacuum domain."""
|
||||
assert trait.StartStopTrait.supported(vacuum.DOMAIN, 0)
|
||||
assert trait.StartStopTrait.supported(vacuum.DOMAIN, 0, None)
|
||||
|
||||
trt = trait.StartStopTrait(hass, State('vacuum.bla', vacuum.STATE_PAUSED, {
|
||||
ATTR_SUPPORTED_FEATURES: vacuum.SUPPORT_PAUSE,
|
||||
|
@ -452,9 +454,9 @@ async def test_startstop_vacuum(hass):
|
|||
|
||||
async def test_color_spectrum_light(hass):
|
||||
"""Test ColorSpectrum trait support for light domain."""
|
||||
assert not trait.ColorSpectrumTrait.supported(light.DOMAIN, 0)
|
||||
assert not trait.ColorSpectrumTrait.supported(light.DOMAIN, 0, None)
|
||||
assert trait.ColorSpectrumTrait.supported(light.DOMAIN,
|
||||
light.SUPPORT_COLOR)
|
||||
light.SUPPORT_COLOR, None)
|
||||
|
||||
trt = trait.ColorSpectrumTrait(hass, State('light.bla', STATE_ON, {
|
||||
light.ATTR_HS_COLOR: (0, 94),
|
||||
|
@ -496,9 +498,10 @@ async def test_color_spectrum_light(hass):
|
|||
|
||||
async def test_color_temperature_light(hass):
|
||||
"""Test ColorTemperature trait support for light domain."""
|
||||
assert not trait.ColorTemperatureTrait.supported(light.DOMAIN, 0)
|
||||
assert not trait.ColorTemperatureTrait.supported(light.DOMAIN, 0, None)
|
||||
assert trait.ColorTemperatureTrait.supported(light.DOMAIN,
|
||||
light.SUPPORT_COLOR_TEMP)
|
||||
light.SUPPORT_COLOR_TEMP,
|
||||
None)
|
||||
|
||||
trt = trait.ColorTemperatureTrait(hass, State('light.bla', STATE_ON, {
|
||||
light.ATTR_MIN_MIREDS: 200,
|
||||
|
@ -552,9 +555,10 @@ async def test_color_temperature_light(hass):
|
|||
|
||||
async def test_color_temperature_light_bad_temp(hass):
|
||||
"""Test ColorTemperature trait support for light domain."""
|
||||
assert not trait.ColorTemperatureTrait.supported(light.DOMAIN, 0)
|
||||
assert not trait.ColorTemperatureTrait.supported(light.DOMAIN, 0, None)
|
||||
assert trait.ColorTemperatureTrait.supported(light.DOMAIN,
|
||||
light.SUPPORT_COLOR_TEMP)
|
||||
light.SUPPORT_COLOR_TEMP,
|
||||
None)
|
||||
|
||||
trt = trait.ColorTemperatureTrait(hass, State('light.bla', STATE_ON, {
|
||||
light.ATTR_MIN_MIREDS: 200,
|
||||
|
@ -568,7 +572,7 @@ async def test_color_temperature_light_bad_temp(hass):
|
|||
|
||||
async def test_scene_scene(hass):
|
||||
"""Test Scene trait support for scene domain."""
|
||||
assert trait.SceneTrait.supported(scene.DOMAIN, 0)
|
||||
assert trait.SceneTrait.supported(scene.DOMAIN, 0, None)
|
||||
|
||||
trt = trait.SceneTrait(hass, State('scene.bla', scene.STATE), BASIC_CONFIG)
|
||||
assert trt.sync_attributes() == {}
|
||||
|
@ -585,7 +589,7 @@ async def test_scene_scene(hass):
|
|||
|
||||
async def test_scene_script(hass):
|
||||
"""Test Scene trait support for script domain."""
|
||||
assert trait.SceneTrait.supported(script.DOMAIN, 0)
|
||||
assert trait.SceneTrait.supported(script.DOMAIN, 0, None)
|
||||
|
||||
trt = trait.SceneTrait(hass, State('script.bla', STATE_OFF), BASIC_CONFIG)
|
||||
assert trt.sync_attributes() == {}
|
||||
|
@ -606,9 +610,9 @@ async def test_scene_script(hass):
|
|||
|
||||
async def test_temperature_setting_climate_onoff(hass):
|
||||
"""Test TemperatureSetting trait support for climate domain - range."""
|
||||
assert not trait.TemperatureSettingTrait.supported(climate.DOMAIN, 0)
|
||||
assert not trait.TemperatureSettingTrait.supported(climate.DOMAIN, 0, None)
|
||||
assert trait.TemperatureSettingTrait.supported(
|
||||
climate.DOMAIN, climate.SUPPORT_OPERATION_MODE)
|
||||
climate.DOMAIN, climate.SUPPORT_OPERATION_MODE, None)
|
||||
|
||||
hass.config.units.temperature_unit = TEMP_FAHRENHEIT
|
||||
|
||||
|
@ -650,9 +654,9 @@ async def test_temperature_setting_climate_onoff(hass):
|
|||
|
||||
async def test_temperature_setting_climate_range(hass):
|
||||
"""Test TemperatureSetting trait support for climate domain - range."""
|
||||
assert not trait.TemperatureSettingTrait.supported(climate.DOMAIN, 0)
|
||||
assert not trait.TemperatureSettingTrait.supported(climate.DOMAIN, 0, None)
|
||||
assert trait.TemperatureSettingTrait.supported(
|
||||
climate.DOMAIN, climate.SUPPORT_OPERATION_MODE)
|
||||
climate.DOMAIN, climate.SUPPORT_OPERATION_MODE, None)
|
||||
|
||||
hass.config.units.temperature_unit = TEMP_FAHRENHEIT
|
||||
|
||||
|
@ -725,9 +729,9 @@ async def test_temperature_setting_climate_range(hass):
|
|||
|
||||
async def test_temperature_setting_climate_setpoint(hass):
|
||||
"""Test TemperatureSetting trait support for climate domain - setpoint."""
|
||||
assert not trait.TemperatureSettingTrait.supported(climate.DOMAIN, 0)
|
||||
assert not trait.TemperatureSettingTrait.supported(climate.DOMAIN, 0, None)
|
||||
assert trait.TemperatureSettingTrait.supported(
|
||||
climate.DOMAIN, climate.SUPPORT_OPERATION_MODE)
|
||||
climate.DOMAIN, climate.SUPPORT_OPERATION_MODE, None)
|
||||
|
||||
hass.config.units.temperature_unit = TEMP_CELSIUS
|
||||
|
||||
|
@ -825,7 +829,8 @@ async def test_temperature_setting_climate_setpoint_auto(hass):
|
|||
|
||||
async def test_lock_unlock_lock(hass):
|
||||
"""Test LockUnlock trait locking support for lock domain."""
|
||||
assert trait.LockUnlockTrait.supported(lock.DOMAIN, lock.SUPPORT_OPEN)
|
||||
assert trait.LockUnlockTrait.supported(lock.DOMAIN, lock.SUPPORT_OPEN,
|
||||
None)
|
||||
|
||||
trt = trait.LockUnlockTrait(hass,
|
||||
State('lock.front_door', lock.STATE_UNLOCKED),
|
||||
|
@ -850,7 +855,8 @@ async def test_lock_unlock_lock(hass):
|
|||
|
||||
async def test_lock_unlock_unlock(hass):
|
||||
"""Test LockUnlock trait unlocking support for lock domain."""
|
||||
assert trait.LockUnlockTrait.supported(lock.DOMAIN, lock.SUPPORT_OPEN)
|
||||
assert trait.LockUnlockTrait.supported(lock.DOMAIN, lock.SUPPORT_OPEN,
|
||||
None)
|
||||
|
||||
trt = trait.LockUnlockTrait(hass,
|
||||
State('lock.front_door', lock.STATE_LOCKED),
|
||||
|
@ -887,7 +893,8 @@ async def test_lock_unlock_unlock(hass):
|
|||
|
||||
async def test_fan_speed(hass):
|
||||
"""Test FanSpeed trait speed control support for fan domain."""
|
||||
assert trait.FanSpeedTrait.supported(fan.DOMAIN, fan.SUPPORT_SET_SPEED)
|
||||
assert trait.FanSpeedTrait.supported(fan.DOMAIN, fan.SUPPORT_SET_SPEED,
|
||||
None)
|
||||
|
||||
trt = trait.FanSpeedTrait(
|
||||
hass, State(
|
||||
|
@ -970,7 +977,7 @@ async def test_fan_speed(hass):
|
|||
async def test_modes(hass):
|
||||
"""Test Mode trait."""
|
||||
assert trait.ModesTrait.supported(
|
||||
media_player.DOMAIN, media_player.SUPPORT_SELECT_SOURCE)
|
||||
media_player.DOMAIN, media_player.SUPPORT_SELECT_SOURCE, None)
|
||||
|
||||
trt = trait.ModesTrait(
|
||||
hass, State(
|
||||
|
@ -1056,9 +1063,9 @@ async def test_modes(hass):
|
|||
|
||||
|
||||
async def test_openclose_cover(hass):
|
||||
"""Test cover trait."""
|
||||
"""Test OpenClose trait support for cover domain."""
|
||||
assert trait.OpenCloseTrait.supported(cover.DOMAIN,
|
||||
cover.SUPPORT_SET_POSITION)
|
||||
cover.SUPPORT_SET_POSITION, None)
|
||||
|
||||
# No position
|
||||
trt = trait.OpenCloseTrait(hass, State('cover.bla', cover.STATE_OPEN, {
|
||||
|
@ -1098,3 +1105,40 @@ async def test_openclose_cover(hass):
|
|||
ATTR_ENTITY_ID: 'cover.bla',
|
||||
cover.ATTR_POSITION: 50
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize('device_class', (
|
||||
binary_sensor.DEVICE_CLASS_DOOR,
|
||||
binary_sensor.DEVICE_CLASS_GARAGE_DOOR,
|
||||
binary_sensor.DEVICE_CLASS_LOCK,
|
||||
binary_sensor.DEVICE_CLASS_OPENING,
|
||||
binary_sensor.DEVICE_CLASS_WINDOW,
|
||||
))
|
||||
async def test_openclose_binary_sensor(hass, device_class):
|
||||
"""Test OpenClose trait support for binary_sensor domain."""
|
||||
assert trait.OpenCloseTrait.supported(binary_sensor.DOMAIN,
|
||||
0, device_class)
|
||||
|
||||
trt = trait.OpenCloseTrait(hass, State('binary_sensor.test', STATE_ON, {
|
||||
ATTR_DEVICE_CLASS: device_class,
|
||||
}), BASIC_CONFIG)
|
||||
|
||||
assert trt.sync_attributes() == {
|
||||
'queryOnlyOpenClose': True,
|
||||
}
|
||||
|
||||
assert trt.query_attributes() == {
|
||||
'openPercent': 100
|
||||
}
|
||||
|
||||
trt = trait.OpenCloseTrait(hass, State('binary_sensor.test', STATE_OFF, {
|
||||
ATTR_DEVICE_CLASS: device_class,
|
||||
}), BASIC_CONFIG)
|
||||
|
||||
assert trt.sync_attributes() == {
|
||||
'queryOnlyOpenClose': True,
|
||||
}
|
||||
|
||||
assert trt.query_attributes() == {
|
||||
'openPercent': 0
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue