Return state when changing optimistic covers (#23498)

This commit is contained in:
Paulus Schoutsen 2019-04-28 12:09:20 -07:00 committed by GitHub
parent 2f45a7e3b9
commit 0f49a9cb7b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 105 additions and 39 deletions

View file

@ -1027,6 +1027,8 @@ class OpenCloseTrait(_Trait):
COMMAND_OPENCLOSE COMMAND_OPENCLOSE
] ]
override_position = None
@staticmethod @staticmethod
def supported(domain, features, device_class): def supported(domain, features, device_class):
"""Test if state is supported.""" """Test if state is supported."""
@ -1043,20 +1045,22 @@ class OpenCloseTrait(_Trait):
def sync_attributes(self): def sync_attributes(self):
"""Return opening direction.""" """Return opening direction."""
attrs = {} response = {}
if self.state.domain == binary_sensor.DOMAIN: if self.state.domain == binary_sensor.DOMAIN:
attrs['queryOnlyOpenClose'] = True response['queryOnlyOpenClose'] = True
return attrs return response
def query_attributes(self): def query_attributes(self):
"""Return state query attributes.""" """Return state query attributes."""
domain = self.state.domain domain = self.state.domain
response = {} response = {}
if domain == cover.DOMAIN: if self.override_position is not None:
# When it's an assumed state, we will always report it as 50% response['openPercent'] = self.override_position
# Google will not issue an open command if the assumed state is
# open, even if that is currently incorrect. elif domain == cover.DOMAIN:
# When it's an assumed state, we will return that querying state
# is not supported.
if self.state.attributes.get(ATTR_ASSUMED_STATE): if self.state.attributes.get(ATTR_ASSUMED_STATE):
raise SmartHomeError( raise SmartHomeError(
ERR_NOT_SUPPORTED, ERR_NOT_SUPPORTED,
@ -1067,7 +1071,7 @@ class OpenCloseTrait(_Trait):
ERR_NOT_SUPPORTED, ERR_NOT_SUPPORTED,
'Querying state is not supported') 'Querying state is not supported')
position = self.state.attributes.get( position = self.override_position or self.state.attributes.get(
cover.ATTR_CURRENT_POSITION cover.ATTR_CURRENT_POSITION
) )
@ -1096,7 +1100,6 @@ class OpenCloseTrait(_Trait):
): ):
_verify_pin_challenge(data, challenge) _verify_pin_challenge(data, challenge)
position = self.state.attributes.get(cover.ATTR_CURRENT_POSITION)
if params['openPercent'] == 0: if params['openPercent'] == 0:
await self.hass.services.async_call( await self.hass.services.async_call(
cover.DOMAIN, cover.SERVICE_CLOSE_COVER, { cover.DOMAIN, cover.SERVICE_CLOSE_COVER, {
@ -1107,7 +1110,8 @@ class OpenCloseTrait(_Trait):
cover.DOMAIN, cover.SERVICE_OPEN_COVER, { cover.DOMAIN, cover.SERVICE_OPEN_COVER, {
ATTR_ENTITY_ID: self.state.entity_id ATTR_ENTITY_ID: self.state.entity_id
}, blocking=True, context=data.context) }, blocking=True, context=data.context)
elif position is not None: elif (self.state.attributes.get(ATTR_SUPPORTED_FEATURES, 0) &
cover.SUPPORT_SET_POSITION):
await self.hass.services.async_call( await self.hass.services.async_call(
cover.DOMAIN, cover.SERVICE_SET_COVER_POSITION, { cover.DOMAIN, cover.SERVICE_SET_COVER_POSITION, {
ATTR_ENTITY_ID: self.state.entity_id, ATTR_ENTITY_ID: self.state.entity_id,
@ -1118,6 +1122,11 @@ class OpenCloseTrait(_Trait):
ERR_FUNCTION_NOT_SUPPORTED, ERR_FUNCTION_NOT_SUPPORTED,
'Setting a position is not supported') 'Setting a position is not supported')
if (self.state.attributes.get(ATTR_ASSUMED_STATE) or
self.state.state == STATE_UNKNOWN):
print("YOO")
self.override_position = params['openPercent']
@register_trait @register_trait
class VolumeTrait(_Trait): class VolumeTrait(_Trait):

View file

@ -1109,36 +1109,9 @@ async def test_openclose_cover(hass):
assert trait.OpenCloseTrait.supported(cover.DOMAIN, assert trait.OpenCloseTrait.supported(cover.DOMAIN,
cover.SUPPORT_SET_POSITION, None) cover.SUPPORT_SET_POSITION, None)
# No position
trt = trait.OpenCloseTrait(hass, State('cover.bla', cover.STATE_OPEN, { trt = trait.OpenCloseTrait(hass, State('cover.bla', cover.STATE_OPEN, {
}), BASIC_CONFIG) cover.ATTR_CURRENT_POSITION: 75,
ATTR_SUPPORTED_FEATURES: cover.SUPPORT_SET_POSITION,
assert trt.sync_attributes() == {}
assert trt.query_attributes() == {
'openPercent': 100
}
# No state
trt = trait.OpenCloseTrait(hass, State('cover.bla', STATE_UNKNOWN, {
}), BASIC_CONFIG)
assert trt.sync_attributes() == {}
with pytest.raises(helpers.SmartHomeError):
trt.query_attributes()
# Assumed state
trt = trait.OpenCloseTrait(hass, State('cover.bla', cover.STATE_OPEN, {
ATTR_ASSUMED_STATE: True,
}), BASIC_CONFIG)
assert trt.sync_attributes() == {}
with pytest.raises(helpers.SmartHomeError):
trt.query_attributes()
trt = trait.OpenCloseTrait(hass, State('cover.bla', cover.STATE_OPEN, {
cover.ATTR_CURRENT_POSITION: 75
}), BASIC_CONFIG) }), BASIC_CONFIG)
assert trt.sync_attributes() == {} assert trt.sync_attributes() == {}
@ -1158,6 +1131,89 @@ async def test_openclose_cover(hass):
} }
async def test_openclose_cover_unknown_state(hass):
"""Test OpenClose trait support for cover domain with unknown state."""
assert helpers.get_google_type(cover.DOMAIN, None) is not None
assert trait.OpenCloseTrait.supported(cover.DOMAIN,
cover.SUPPORT_SET_POSITION, None)
# No state
trt = trait.OpenCloseTrait(hass, State('cover.bla', STATE_UNKNOWN, {
}), BASIC_CONFIG)
assert trt.sync_attributes() == {}
with pytest.raises(helpers.SmartHomeError):
trt.query_attributes()
calls = async_mock_service(
hass, cover.DOMAIN, cover.SERVICE_OPEN_COVER)
await trt.execute(
trait.COMMAND_OPENCLOSE, BASIC_DATA,
{'openPercent': 100}, {})
assert len(calls) == 1
assert calls[0].data == {
ATTR_ENTITY_ID: 'cover.bla',
}
assert trt.query_attributes() == {'openPercent': 100}
async def test_openclose_cover_assumed_state(hass):
"""Test OpenClose trait support for cover domain."""
assert helpers.get_google_type(cover.DOMAIN, None) is not None
assert trait.OpenCloseTrait.supported(cover.DOMAIN,
cover.SUPPORT_SET_POSITION, None)
trt = trait.OpenCloseTrait(hass, State('cover.bla', cover.STATE_OPEN, {
ATTR_ASSUMED_STATE: True,
ATTR_SUPPORTED_FEATURES: cover.SUPPORT_SET_POSITION,
}), BASIC_CONFIG)
assert trt.sync_attributes() == {}
with pytest.raises(helpers.SmartHomeError):
trt.query_attributes()
calls = async_mock_service(
hass, cover.DOMAIN, cover.SERVICE_SET_COVER_POSITION)
await trt.execute(
trait.COMMAND_OPENCLOSE, BASIC_DATA,
{'openPercent': 40}, {})
assert len(calls) == 1
assert calls[0].data == {
ATTR_ENTITY_ID: 'cover.bla',
cover.ATTR_POSITION: 40
}
assert trt.query_attributes() == {'openPercent': 40}
async def test_openclose_cover_no_position(hass):
"""Test OpenClose trait support for cover domain."""
assert helpers.get_google_type(cover.DOMAIN, None) is not None
assert trait.OpenCloseTrait.supported(cover.DOMAIN,
cover.SUPPORT_SET_POSITION, None)
trt = trait.OpenCloseTrait(hass, State('cover.bla', cover.STATE_OPEN, {
}), BASIC_CONFIG)
assert trt.sync_attributes() == {}
assert trt.query_attributes() == {
'openPercent': 100
}
calls = async_mock_service(
hass, cover.DOMAIN, cover.SERVICE_CLOSE_COVER)
await trt.execute(
trait.COMMAND_OPENCLOSE, BASIC_DATA,
{'openPercent': 0}, {})
assert len(calls) == 1
assert calls[0].data == {
ATTR_ENTITY_ID: 'cover.bla',
}
@pytest.mark.parametrize('device_class', ( @pytest.mark.parametrize('device_class', (
cover.DEVICE_CLASS_DOOR, cover.DEVICE_CLASS_DOOR,
cover.DEVICE_CLASS_GARAGE, cover.DEVICE_CLASS_GARAGE,
@ -1170,6 +1226,7 @@ async def test_openclose_cover_secure(hass, device_class):
trt = trait.OpenCloseTrait(hass, State('cover.bla', cover.STATE_OPEN, { trt = trait.OpenCloseTrait(hass, State('cover.bla', cover.STATE_OPEN, {
ATTR_DEVICE_CLASS: device_class, ATTR_DEVICE_CLASS: device_class,
ATTR_SUPPORTED_FEATURES: cover.SUPPORT_SET_POSITION,
cover.ATTR_CURRENT_POSITION: 75 cover.ATTR_CURRENT_POSITION: 75
}), PIN_CONFIG) }), PIN_CONFIG)