Bump yalexs to 2.0.0 (#111706)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
ffcbab1c20
commit
e631224372
7 changed files with 133 additions and 22 deletions
|
@ -306,6 +306,13 @@ class AugustData(AugustSubscriberMixin):
|
|||
exc_info=err,
|
||||
)
|
||||
|
||||
async def refresh_camera_by_id(self, device_id: str) -> None:
|
||||
"""Re-fetch doorbell/camera data from API."""
|
||||
await self._async_update_device_detail(
|
||||
self._doorbells_by_id[device_id],
|
||||
self._api.async_get_doorbell_detail,
|
||||
)
|
||||
|
||||
async def _async_refresh_device_detail_by_id(self, device_id: str) -> None:
|
||||
if device_id in self._locks_by_id:
|
||||
if self.activity_stream and self.activity_stream.pubnub.connected:
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from aiohttp import ClientSession
|
||||
from yalexs.activity import ActivityType
|
||||
from yalexs.doorbell import Doorbell
|
||||
from yalexs.const import Brand
|
||||
from yalexs.doorbell import ContentTokenExpired, Doorbell
|
||||
from yalexs.util import update_doorbell_image_from_activity
|
||||
|
||||
from homeassistant.components.camera import Camera
|
||||
|
@ -17,6 +20,8 @@ from . import AugustData
|
|||
from .const import DEFAULT_NAME, DEFAULT_TIMEOUT, DOMAIN
|
||||
from .entity import AugustEntityMixin
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
|
@ -48,6 +53,7 @@ class AugustCamera(AugustEntityMixin, Camera):
|
|||
self._timeout = timeout
|
||||
self._session = session
|
||||
self._image_url = None
|
||||
self._content_token = None
|
||||
self._image_content = None
|
||||
self._attr_unique_id = f"{self._device_id:s}_camera"
|
||||
self._attr_motion_detection_enabled = True
|
||||
|
@ -63,6 +69,12 @@ class AugustCamera(AugustEntityMixin, Camera):
|
|||
"""Return the camera model."""
|
||||
return self._detail.model
|
||||
|
||||
async def _async_update(self):
|
||||
"""Update device."""
|
||||
_LOGGER.debug("async_update called %s", self._detail.device_name)
|
||||
await self._data.refresh_camera_by_id(self._device_id)
|
||||
self._update_from_data()
|
||||
|
||||
@callback
|
||||
def _update_from_data(self) -> None:
|
||||
"""Get the latest state of the sensor."""
|
||||
|
@ -70,7 +82,6 @@ class AugustCamera(AugustEntityMixin, Camera):
|
|||
self._device_id,
|
||||
{ActivityType.DOORBELL_MOTION, ActivityType.DOORBELL_IMAGE_CAPTURE},
|
||||
)
|
||||
|
||||
if doorbell_activity is not None:
|
||||
update_doorbell_image_from_activity(self._detail, doorbell_activity)
|
||||
|
||||
|
@ -82,7 +93,23 @@ class AugustCamera(AugustEntityMixin, Camera):
|
|||
|
||||
if self._image_url is not self._detail.image_url:
|
||||
self._image_url = self._detail.image_url
|
||||
self._image_content = await self._detail.async_get_doorbell_image(
|
||||
self._session, timeout=self._timeout
|
||||
self._content_token = self._detail.content_token or self._content_token
|
||||
_LOGGER.debug(
|
||||
"calling doorbell async_get_doorbell_image, %s",
|
||||
self._detail.device_name,
|
||||
)
|
||||
try:
|
||||
self._image_content = await self._detail.async_get_doorbell_image(
|
||||
self._session, timeout=self._timeout
|
||||
)
|
||||
except ContentTokenExpired:
|
||||
if self._data.brand == Brand.YALE_HOME:
|
||||
_LOGGER.debug(
|
||||
"Error fetching camera image, updating content-token from api to retry"
|
||||
)
|
||||
await self._async_update()
|
||||
self._image_content = await self._detail.async_get_doorbell_image(
|
||||
self._session, timeout=self._timeout
|
||||
)
|
||||
|
||||
return self._image_content
|
||||
|
|
|
@ -28,5 +28,5 @@
|
|||
"documentation": "https://www.home-assistant.io/integrations/august",
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["pubnub", "yalexs"],
|
||||
"requirements": ["yalexs==1.11.4", "yalexs-ble==2.4.2"]
|
||||
"requirements": ["yalexs==2.0.0", "yalexs-ble==2.4.2"]
|
||||
}
|
||||
|
|
|
@ -2893,7 +2893,7 @@ yalesmartalarmclient==0.3.9
|
|||
yalexs-ble==2.4.2
|
||||
|
||||
# homeassistant.components.august
|
||||
yalexs==1.11.4
|
||||
yalexs==2.0.0
|
||||
|
||||
# homeassistant.components.yeelight
|
||||
yeelight==0.7.14
|
||||
|
|
|
@ -2228,7 +2228,7 @@ yalesmartalarmclient==0.3.9
|
|||
yalexs-ble==2.4.2
|
||||
|
||||
# homeassistant.components.august
|
||||
yalexs==1.11.4
|
||||
yalexs==2.0.0
|
||||
|
||||
# homeassistant.components.yeelight
|
||||
yeelight==0.7.14
|
||||
|
|
|
@ -26,11 +26,12 @@ from yalexs.activity import (
|
|||
LockOperationActivity,
|
||||
)
|
||||
from yalexs.authenticator import AuthenticationState
|
||||
from yalexs.const import Brand
|
||||
from yalexs.doorbell import Doorbell, DoorbellDetail
|
||||
from yalexs.lock import Lock, LockDetail
|
||||
from yalexs.pubnub_async import AugustPubNub
|
||||
|
||||
from homeassistant.components.august.const import CONF_LOGIN_METHOD, DOMAIN
|
||||
from homeassistant.components.august.const import CONF_BRAND, CONF_LOGIN_METHOD, DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
@ -38,13 +39,14 @@ from homeassistant.core import HomeAssistant
|
|||
from tests.common import MockConfigEntry, load_fixture
|
||||
|
||||
|
||||
def _mock_get_config():
|
||||
def _mock_get_config(brand: Brand = Brand.AUGUST):
|
||||
"""Return a default august config."""
|
||||
return {
|
||||
DOMAIN: {
|
||||
CONF_LOGIN_METHOD: "email",
|
||||
CONF_USERNAME: "mocked_username",
|
||||
CONF_PASSWORD: "mocked_password",
|
||||
CONF_BRAND: brand,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,7 +61,7 @@ def _mock_authenticator(auth_state):
|
|||
@patch("homeassistant.components.august.gateway.ApiAsync")
|
||||
@patch("homeassistant.components.august.gateway.AuthenticatorAsync.async_authenticate")
|
||||
async def _mock_setup_august(
|
||||
hass, api_instance, pubnub_mock, authenticate_mock, api_mock
|
||||
hass, api_instance, pubnub_mock, authenticate_mock, api_mock, brand
|
||||
):
|
||||
"""Set up august integration."""
|
||||
authenticate_mock.side_effect = MagicMock(
|
||||
|
@ -70,7 +72,7 @@ async def _mock_setup_august(
|
|||
api_mock.return_value = api_instance
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=_mock_get_config()[DOMAIN],
|
||||
data=_mock_get_config(brand)[DOMAIN],
|
||||
options={},
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
@ -88,21 +90,26 @@ async def _create_august_with_devices(
|
|||
api_call_side_effects: dict[str, Any] | None = None,
|
||||
activities: list[Any] | None = None,
|
||||
pubnub: AugustPubNub | None = None,
|
||||
brand: Brand = Brand.AUGUST,
|
||||
) -> ConfigEntry:
|
||||
entry, _ = await _create_august_api_with_devices(
|
||||
hass, devices, api_call_side_effects, activities, pubnub
|
||||
hass, devices, api_call_side_effects, activities, pubnub, brand
|
||||
)
|
||||
return entry
|
||||
|
||||
|
||||
async def _create_august_api_with_devices( # noqa: C901
|
||||
hass, devices, api_call_side_effects=None, activities=None, pubnub=None
|
||||
hass,
|
||||
devices,
|
||||
api_call_side_effects=None,
|
||||
activities=None,
|
||||
pubnub=None,
|
||||
brand=Brand.AUGUST,
|
||||
):
|
||||
if api_call_side_effects is None:
|
||||
api_call_side_effects = {}
|
||||
if pubnub is None:
|
||||
pubnub = AugustPubNub()
|
||||
|
||||
device_data = {"doorbells": [], "locks": []}
|
||||
for device in devices:
|
||||
if isinstance(device, LockDetail):
|
||||
|
@ -111,7 +118,13 @@ async def _create_august_api_with_devices( # noqa: C901
|
|||
)
|
||||
elif isinstance(device, DoorbellDetail):
|
||||
device_data["doorbells"].append(
|
||||
{"base": _mock_august_doorbell(device.device_id), "detail": device}
|
||||
{
|
||||
"base": _mock_august_doorbell(
|
||||
deviceid=device.device_id,
|
||||
brand=device._data.get("brand", Brand.AUGUST),
|
||||
),
|
||||
"detail": device,
|
||||
}
|
||||
)
|
||||
else:
|
||||
raise ValueError # noqa: TRY004
|
||||
|
@ -182,7 +195,7 @@ async def _create_august_api_with_devices( # noqa: C901
|
|||
)
|
||||
|
||||
api_instance, entry = await _mock_setup_august_with_api_side_effects(
|
||||
hass, api_call_side_effects, pubnub
|
||||
hass, api_call_side_effects, pubnub, brand
|
||||
)
|
||||
|
||||
if device_data["locks"]:
|
||||
|
@ -193,7 +206,9 @@ async def _create_august_api_with_devices( # noqa: C901
|
|||
return entry, api_instance
|
||||
|
||||
|
||||
async def _mock_setup_august_with_api_side_effects(hass, api_call_side_effects, pubnub):
|
||||
async def _mock_setup_august_with_api_side_effects(
|
||||
hass, api_call_side_effects, pubnub, brand=Brand.AUGUST
|
||||
):
|
||||
api_instance = MagicMock(name="Api")
|
||||
|
||||
if api_call_side_effects["get_lock_detail"]:
|
||||
|
@ -236,7 +251,9 @@ async def _mock_setup_august_with_api_side_effects(hass, api_call_side_effects,
|
|||
api_instance.async_status_async = AsyncMock()
|
||||
api_instance.async_get_user = AsyncMock(return_value={"UserID": "abc"})
|
||||
|
||||
return api_instance, await _mock_setup_august(hass, api_instance, pubnub)
|
||||
return api_instance, await _mock_setup_august(
|
||||
hass, api_instance, pubnub, brand=brand
|
||||
)
|
||||
|
||||
|
||||
def _mock_august_authentication(token_text, token_timestamp, state):
|
||||
|
@ -253,13 +270,18 @@ def _mock_august_lock(lockid="mocklockid1", houseid="mockhouseid1"):
|
|||
return Lock(lockid, _mock_august_lock_data(lockid=lockid, houseid=houseid))
|
||||
|
||||
|
||||
def _mock_august_doorbell(deviceid="mockdeviceid1", houseid="mockhouseid1"):
|
||||
def _mock_august_doorbell(
|
||||
deviceid="mockdeviceid1", houseid="mockhouseid1", brand=Brand.AUGUST
|
||||
):
|
||||
return Doorbell(
|
||||
deviceid, _mock_august_doorbell_data(deviceid=deviceid, houseid=houseid)
|
||||
deviceid,
|
||||
_mock_august_doorbell_data(deviceid=deviceid, houseid=houseid, brand=brand),
|
||||
)
|
||||
|
||||
|
||||
def _mock_august_doorbell_data(deviceid="mockdeviceid1", houseid="mockhouseid1"):
|
||||
def _mock_august_doorbell_data(
|
||||
deviceid="mockdeviceid1", houseid="mockhouseid1", brand=Brand.AUGUST
|
||||
):
|
||||
return {
|
||||
"_id": deviceid,
|
||||
"DeviceID": deviceid,
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
from http import HTTPStatus
|
||||
from unittest.mock import patch
|
||||
|
||||
from yalexs.const import Brand
|
||||
from yalexs.doorbell import ContentTokenExpired
|
||||
|
||||
from homeassistant.const import STATE_IDLE
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
|
@ -20,7 +23,7 @@ async def test_create_doorbell(
|
|||
with patch.object(
|
||||
doorbell_one, "async_get_doorbell_image", create=False, return_value="image"
|
||||
):
|
||||
await _create_august_with_devices(hass, [doorbell_one])
|
||||
await _create_august_with_devices(hass, [doorbell_one], brand=Brand.AUGUST)
|
||||
|
||||
camera_k98gidt45gul_name_camera = hass.states.get(
|
||||
"camera.k98gidt45gul_name_camera"
|
||||
|
@ -36,3 +39,55 @@ async def test_create_doorbell(
|
|||
assert resp.status == HTTPStatus.OK
|
||||
body = await resp.text()
|
||||
assert body == "image"
|
||||
|
||||
|
||||
async def test_doorbell_refresh_content_token_recover(
|
||||
hass: HomeAssistant, hass_client_no_auth: ClientSessionGenerator
|
||||
) -> None:
|
||||
"""Test camera image content token expired."""
|
||||
doorbell_two = await _mock_doorbell_from_fixture(hass, "get_doorbell.json")
|
||||
with patch.object(
|
||||
doorbell_two,
|
||||
"async_get_doorbell_image",
|
||||
create=False,
|
||||
side_effect=[ContentTokenExpired, "image"],
|
||||
):
|
||||
await _create_august_with_devices(
|
||||
hass,
|
||||
[doorbell_two],
|
||||
brand=Brand.YALE_HOME,
|
||||
)
|
||||
url = hass.states.get("camera.k98gidt45gul_name_camera").attributes[
|
||||
"entity_picture"
|
||||
]
|
||||
|
||||
client = await hass_client_no_auth()
|
||||
resp = await client.get(url)
|
||||
assert resp.status == HTTPStatus.OK
|
||||
body = await resp.text()
|
||||
assert body == "image"
|
||||
|
||||
|
||||
async def test_doorbell_refresh_content_token_fail(
|
||||
hass: HomeAssistant, hass_client_no_auth: ClientSessionGenerator
|
||||
) -> None:
|
||||
"""Test camera image content token expired."""
|
||||
doorbell_two = await _mock_doorbell_from_fixture(hass, "get_doorbell.json")
|
||||
with patch.object(
|
||||
doorbell_two,
|
||||
"async_get_doorbell_image",
|
||||
create=False,
|
||||
side_effect=ContentTokenExpired,
|
||||
):
|
||||
await _create_august_with_devices(
|
||||
hass,
|
||||
[doorbell_two],
|
||||
brand=Brand.YALE_HOME,
|
||||
)
|
||||
url = hass.states.get("camera.k98gidt45gul_name_camera").attributes[
|
||||
"entity_picture"
|
||||
]
|
||||
|
||||
client = await hass_client_no_auth()
|
||||
resp = await client.get(url)
|
||||
assert resp.status == HTTPStatus.INTERNAL_SERVER_ERROR
|
||||
|
|
Loading…
Add table
Reference in a new issue