diff --git a/homeassistant/components/google_assistant/trait.py b/homeassistant/components/google_assistant/trait.py index 11bb4f28aeb..cb2bf688ad0 100644 --- a/homeassistant/components/google_assistant/trait.py +++ b/homeassistant/components/google_assistant/trait.py @@ -742,11 +742,10 @@ class LockUnlockTrait(_Trait): async def execute(self, command, data, params, challenge): """Execute an LockUnlock command.""" - _verify_pin_challenge(data, challenge) - if params['lock']: service = lock.SERVICE_LOCK else: + _verify_pin_challenge(data, challenge) service = lock.SERVICE_UNLOCK await self.hass.services.async_call(lock.DOMAIN, service, { @@ -1095,36 +1094,36 @@ class OpenCloseTrait(_Trait): domain = self.state.domain if domain == cover.DOMAIN: - if self.state.attributes.get(ATTR_DEVICE_CLASS) in ( - cover.DEVICE_CLASS_DOOR, cover.DEVICE_CLASS_GARAGE - ): - _verify_pin_challenge(data, challenge) + svc_params = {ATTR_ENTITY_ID: self.state.entity_id} if params['openPercent'] == 0: - await self.hass.services.async_call( - cover.DOMAIN, cover.SERVICE_CLOSE_COVER, { - ATTR_ENTITY_ID: self.state.entity_id - }, blocking=True, context=data.context) + service = cover.SERVICE_CLOSE_COVER + should_verify = False elif params['openPercent'] == 100: - await self.hass.services.async_call( - cover.DOMAIN, cover.SERVICE_OPEN_COVER, { - ATTR_ENTITY_ID: self.state.entity_id - }, blocking=True, context=data.context) + service = cover.SERVICE_OPEN_COVER + should_verify = True elif (self.state.attributes.get(ATTR_SUPPORTED_FEATURES, 0) & cover.SUPPORT_SET_POSITION): - await self.hass.services.async_call( - cover.DOMAIN, cover.SERVICE_SET_COVER_POSITION, { - ATTR_ENTITY_ID: self.state.entity_id, - cover.ATTR_POSITION: params['openPercent'] - }, blocking=True, context=data.context) + service = cover.SERVICE_SET_COVER_POSITION + should_verify = True + svc_params[cover.ATTR_POSITION] = params['openPercent'] else: raise SmartHomeError( ERR_FUNCTION_NOT_SUPPORTED, 'Setting a position is not supported') + if (should_verify and + self.state.attributes.get(ATTR_DEVICE_CLASS) + in (cover.DEVICE_CLASS_DOOR, + cover.DEVICE_CLASS_GARAGE)): + _verify_pin_challenge(data, challenge) + + await self.hass.services.async_call( + cover.DOMAIN, service, svc_params, + blocking=True, context=data.context) + if (self.state.attributes.get(ATTR_ASSUMED_STATE) or self.state.state == STATE_UNKNOWN): - print("YOO") self.override_position = params['openPercent'] diff --git a/tests/components/google_assistant/test_trait.py b/tests/components/google_assistant/test_trait.py index 3be25b498b5..5e6dadf14f4 100644 --- a/tests/components/google_assistant/test_trait.py +++ b/tests/components/google_assistant/test_trait.py @@ -845,38 +845,20 @@ async def test_lock_unlock_lock(hass): None) trt = trait.LockUnlockTrait(hass, - State('lock.front_door', lock.STATE_UNLOCKED), + State('lock.front_door', lock.STATE_LOCKED), PIN_CONFIG) assert trt.sync_attributes() == {} assert trt.query_attributes() == { - 'isLocked': False + 'isLocked': True } assert trt.can_execute(trait.COMMAND_LOCKUNLOCK, {'lock': True}) calls = async_mock_service(hass, lock.DOMAIN, lock.SERVICE_LOCK) - # No challenge data - with pytest.raises(error.ChallengeNeeded) as err: - await trt.execute( - trait.COMMAND_LOCKUNLOCK, PIN_DATA, {'lock': True}, {}) - assert len(calls) == 0 - assert err.code == const.ERR_CHALLENGE_NEEDED - assert err.challenge_type == const.CHALLENGE_PIN_NEEDED - - # invalid pin - with pytest.raises(error.ChallengeNeeded) as err: - await trt.execute( - trait.COMMAND_LOCKUNLOCK, PIN_DATA, {'lock': True}, - {'pin': 9999}) - assert len(calls) == 0 - assert err.code == const.ERR_CHALLENGE_NEEDED - assert err.challenge_type == const.CHALLENGE_FAILED_PIN_NEEDED - - await trt.execute(trait.COMMAND_LOCKUNLOCK, PIN_DATA, {'lock': True}, - {'pin': '1234'}) + await trt.execute(trait.COMMAND_LOCKUNLOCK, PIN_DATA, {'lock': True}, {}) assert len(calls) == 1 assert calls[0].data == { @@ -908,18 +890,18 @@ async def test_lock_unlock_unlock(hass): with pytest.raises(error.ChallengeNeeded) as err: await trt.execute( trait.COMMAND_LOCKUNLOCK, PIN_DATA, {'lock': False}, {}) - assert len(calls) == 0 - assert err.code == const.ERR_CHALLENGE_NEEDED - assert err.challenge_type == const.CHALLENGE_PIN_NEEDED + assert len(calls) == 0 + assert err.value.code == const.ERR_CHALLENGE_NEEDED + assert err.value.challenge_type == const.CHALLENGE_PIN_NEEDED # invalid pin with pytest.raises(error.ChallengeNeeded) as err: await trt.execute( trait.COMMAND_LOCKUNLOCK, PIN_DATA, {'lock': False}, {'pin': 9999}) - assert len(calls) == 0 - assert err.code == const.ERR_CHALLENGE_NEEDED - assert err.challenge_type == const.CHALLENGE_FAILED_PIN_NEEDED + assert len(calls) == 0 + assert err.value.code == const.ERR_CHALLENGE_NEEDED + assert err.value.challenge_type == const.CHALLENGE_FAILED_PIN_NEEDED await trt.execute( trait.COMMAND_LOCKUNLOCK, PIN_DATA, {'lock': False}, {'pin': '1234'}) @@ -929,6 +911,17 @@ async def test_lock_unlock_unlock(hass): ATTR_ENTITY_ID: 'lock.front_door' } + # Test without pin + trt = trait.LockUnlockTrait(hass, + State('lock.front_door', lock.STATE_LOCKED), + BASIC_CONFIG) + + with pytest.raises(error.SmartHomeError) as err: + await trt.execute( + trait.COMMAND_LOCKUNLOCK, BASIC_DATA, {'lock': False}, {}) + assert len(calls) == 1 + assert err.value.code == const.ERR_CHALLENGE_NOT_SETUP + async def test_fan_speed(hass): """Test FanSpeed trait speed control support for fan domain.""" @@ -1243,18 +1236,18 @@ async def test_openclose_cover_secure(hass, device_class): await trt.execute( trait.COMMAND_OPENCLOSE, PIN_DATA, {'openPercent': 50}, {}) - assert len(calls) == 0 - assert err.code == const.ERR_CHALLENGE_NEEDED - assert err.challenge_type == const.CHALLENGE_PIN_NEEDED + assert len(calls) == 0 + assert err.value.code == const.ERR_CHALLENGE_NEEDED + assert err.value.challenge_type == const.CHALLENGE_PIN_NEEDED # invalid pin with pytest.raises(error.ChallengeNeeded) as err: await trt.execute( trait.COMMAND_OPENCLOSE, PIN_DATA, {'openPercent': 50}, {'pin': '9999'}) - assert len(calls) == 0 - assert err.code == const.ERR_CHALLENGE_NEEDED - assert err.challenge_type == const.CHALLENGE_FAILED_PIN_NEEDED + assert len(calls) == 0 + assert err.value.code == const.ERR_CHALLENGE_NEEDED + assert err.value.challenge_type == const.CHALLENGE_FAILED_PIN_NEEDED await trt.execute( trait.COMMAND_OPENCLOSE, PIN_DATA, @@ -1265,6 +1258,17 @@ async def test_openclose_cover_secure(hass, device_class): cover.ATTR_POSITION: 50 } + # no challenge on close + calls = async_mock_service( + hass, cover.DOMAIN, cover.SERVICE_CLOSE_COVER) + await trt.execute( + trait.COMMAND_OPENCLOSE, PIN_DATA, + {'openPercent': 0}, {}) + assert len(calls) == 1 + assert calls[0].data == { + ATTR_ENTITY_ID: 'cover.bla' + } + @pytest.mark.parametrize('device_class', ( binary_sensor.DEVICE_CLASS_DOOR,