diff --git a/homeassistant/components/august/__init__.py b/homeassistant/components/august/__init__.py index 2be04989064..d521cf559a0 100644 --- a/homeassistant/components/august/__init__.py +++ b/homeassistant/components/august/__init__.py @@ -247,6 +247,15 @@ class AugustData(AugustSubscriberMixin): device_id, ) + async def async_lock_async(self, device_id): + """Lock the device but do not wait for a response since it will come via pubnub.""" + return await self._async_call_api_op_requires_bridge( + device_id, + self._api.async_lock_async, + self._august_gateway.access_token, + device_id, + ) + async def async_unlock(self, device_id): """Unlock the device.""" return await self._async_call_api_op_requires_bridge( @@ -256,6 +265,15 @@ class AugustData(AugustSubscriberMixin): device_id, ) + async def async_unlock_async(self, device_id): + """Unlock the device but do not wait for a response since it will come via pubnub.""" + return await self._async_call_api_op_requires_bridge( + device_id, + self._api.async_unlock_async, + self._august_gateway.access_token, + device_id, + ) + async def _async_call_api_op_requires_bridge( self, device_id, func, *args, **kwargs ): diff --git a/homeassistant/components/august/lock.py b/homeassistant/components/august/lock.py index ae7d6a92d31..8136cba482e 100644 --- a/homeassistant/components/august/lock.py +++ b/homeassistant/components/august/lock.py @@ -48,10 +48,16 @@ class AugustLock(AugustEntityMixin, RestoreEntity, LockEntity): async def async_lock(self, **kwargs): """Lock the device.""" + if self._data.activity_stream.pubnub.connected: + await self._data.async_lock_async(self._device_id) + return await self._call_lock_operation(self._data.async_lock) async def async_unlock(self, **kwargs): """Unlock the device.""" + if self._data.activity_stream.pubnub.connected: + await self._data.async_unlock_async(self._device_id) + return await self._call_lock_operation(self._data.async_unlock) async def _call_lock_operation(self, lock_operation): diff --git a/homeassistant/components/august/manifest.json b/homeassistant/components/august/manifest.json index 201c9ce89aa..c08f25177cc 100644 --- a/homeassistant/components/august/manifest.json +++ b/homeassistant/components/august/manifest.json @@ -2,7 +2,7 @@ "domain": "august", "name": "August", "documentation": "https://www.home-assistant.io/integrations/august", - "requirements": ["yalexs==1.1.16"], + "requirements": ["yalexs==1.1.17"], "codeowners": ["@bdraco"], "dhcp": [ { diff --git a/requirements_all.txt b/requirements_all.txt index 9260cb93a53..a54b3f55c86 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2500,7 +2500,7 @@ xs1-api-client==3.0.0 yalesmartalarmclient==0.3.7 # homeassistant.components.august -yalexs==1.1.16 +yalexs==1.1.17 # homeassistant.components.yeelight yeelight==0.7.8 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 76037cbfc4e..7ee9a2d1875 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1522,7 +1522,7 @@ xmltodict==0.12.0 yalesmartalarmclient==0.3.7 # homeassistant.components.august -yalexs==1.1.16 +yalexs==1.1.17 # homeassistant.components.yeelight yeelight==0.7.8 diff --git a/tests/components/august/mocks.py b/tests/components/august/mocks.py index 13d8f18d0d9..7075eb84d72 100644 --- a/tests/components/august/mocks.py +++ b/tests/components/august/mocks.py @@ -2,8 +2,6 @@ import json import os import time - -# from unittest.mock import AsyncMock from unittest.mock import AsyncMock, MagicMock, PropertyMock, patch from yalexs.activity import ( @@ -207,6 +205,8 @@ async def _mock_setup_august_with_api_side_effects(hass, api_call_side_effects, side_effect=api_call_side_effects["unlock_return_activities"] ) + api_instance.async_unlock_async = AsyncMock() + api_instance.async_lock_async = AsyncMock() api_instance.async_get_user = AsyncMock(return_value={"UserID": "abc"}) return await _mock_setup_august(hass, api_instance, pubnub) diff --git a/tests/components/august/test_lock.py b/tests/components/august/test_lock.py index 9d1c34d917a..56f55138e36 100644 --- a/tests/components/august/test_lock.py +++ b/tests/components/august/test_lock.py @@ -154,6 +154,86 @@ async def test_one_lock_operation(hass): ) +async def test_one_lock_operation_pubnub_connected(hass): + """Test lock and unlock operations are async when pubnub is connected.""" + lock_one = await _mock_doorsense_enabled_august_lock_detail(hass) + assert lock_one.pubsub_channel == "pubsub" + + pubnub = AugustPubNub() + await _create_august_with_devices(hass, [lock_one], pubnub=pubnub) + pubnub.connected = True + + lock_online_with_doorsense_name = hass.states.get("lock.online_with_doorsense_name") + + assert lock_online_with_doorsense_name.state == STATE_LOCKED + + assert lock_online_with_doorsense_name.attributes.get("battery_level") == 92 + assert ( + lock_online_with_doorsense_name.attributes.get("friendly_name") + == "online_with_doorsense Name" + ) + + data = {ATTR_ENTITY_ID: "lock.online_with_doorsense_name"} + assert await hass.services.async_call( + LOCK_DOMAIN, SERVICE_UNLOCK, data, blocking=True + ) + await hass.async_block_till_done() + + pubnub.message( + pubnub, + Mock( + channel=lock_one.pubsub_channel, + timetoken=(dt_util.utcnow().timestamp() + 1) * 10000000, + message={ + "status": "kAugLockState_Unlocked", + }, + ), + ) + await hass.async_block_till_done() + await hass.async_block_till_done() + + lock_online_with_doorsense_name = hass.states.get("lock.online_with_doorsense_name") + assert lock_online_with_doorsense_name.state == STATE_UNLOCKED + + assert lock_online_with_doorsense_name.attributes.get("battery_level") == 92 + assert ( + lock_online_with_doorsense_name.attributes.get("friendly_name") + == "online_with_doorsense Name" + ) + + assert await hass.services.async_call( + LOCK_DOMAIN, SERVICE_LOCK, data, blocking=True + ) + await hass.async_block_till_done() + + pubnub.message( + pubnub, + Mock( + channel=lock_one.pubsub_channel, + timetoken=(dt_util.utcnow().timestamp() + 2) * 10000000, + message={ + "status": "kAugLockState_Locked", + }, + ), + ) + await hass.async_block_till_done() + await hass.async_block_till_done() + + lock_online_with_doorsense_name = hass.states.get("lock.online_with_doorsense_name") + assert lock_online_with_doorsense_name.state == STATE_LOCKED + + # No activity means it will be unavailable until the activity feed has data + entity_registry = er.async_get(hass) + lock_operator_sensor = entity_registry.async_get( + "sensor.online_with_doorsense_name_operator" + ) + assert lock_operator_sensor + assert ( + hass.states.get("sensor.online_with_doorsense_name_operator").state + == STATE_UNKNOWN + ) + + async def test_lock_jammed(hass): """Test lock gets jammed on unlock.""" @@ -273,6 +353,7 @@ async def test_lock_update_via_pubnub(hass): config_entry = await _create_august_with_devices( hass, [lock_one], activities=activities, pubnub=pubnub ) + pubnub.connected = True lock_online_with_doorsense_name = hass.states.get("lock.online_with_doorsense_name")