Fix doorbird models are missing the schedule API (#123033)

* Fix doorbird models are missing the schedule API

fixes #122997

* cover
This commit is contained in:
J. Nick Koston 2024-08-01 15:37:26 -05:00 committed by Franck Nijhof
parent d87366b1e7
commit a624ada8d6
No known key found for this signature in database
GPG key ID: D62583BA8AB11CA3
4 changed files with 37 additions and 18 deletions

View file

@ -5,9 +5,11 @@ from __future__ import annotations
from collections import defaultdict
from dataclasses import dataclass
from functools import cached_property
from http import HTTPStatus
import logging
from typing import Any
from aiohttp import ClientResponseError
from doorbirdpy import (
DoorBird,
DoorBirdScheduleEntry,
@ -170,15 +172,21 @@ class ConfiguredDoorBird:
) -> DoorbirdEventConfig:
"""Get events and unconfigured favorites from http favorites."""
device = self.device
schedule = await device.schedule()
events: list[DoorbirdEvent] = []
unconfigured_favorites: defaultdict[str, list[str]] = defaultdict(list)
try:
schedule = await device.schedule()
except ClientResponseError as ex:
if ex.status == HTTPStatus.NOT_FOUND:
# D301 models do not support schedules
return DoorbirdEventConfig(events, [], unconfigured_favorites)
raise
favorite_input_type = {
output.param: entry.input
for entry in schedule
for output in entry.output
if output.event == HTTP_EVENT_TYPE
}
events: list[DoorbirdEvent] = []
unconfigured_favorites: defaultdict[str, list[str]] = defaultdict(list)
default_event_types = {
self._get_event_name(event): event_type
for event, event_type in DEFAULT_EVENT_TYPES

View file

@ -47,31 +47,30 @@ def get_mock_doorbird_api(
info: dict[str, Any] | None = None,
info_side_effect: Exception | None = None,
schedule: list[DoorBirdScheduleEntry] | None = None,
schedule_side_effect: Exception | None = None,
favorites: dict[str, dict[str, Any]] | None = None,
favorites_side_effect: Exception | None = None,
change_schedule: tuple[bool, int] | None = None,
) -> DoorBird:
"""Return a mock DoorBirdAPI object with return values."""
doorbirdapi_mock = MagicMock(spec_set=DoorBird)
type(doorbirdapi_mock).info = AsyncMock(
side_effect=info_side_effect, return_value=info
api_mock_type = type(doorbirdapi_mock)
api_mock_type.info = AsyncMock(side_effect=info_side_effect, return_value=info)
api_mock_type.favorites = AsyncMock(
side_effect=favorites_side_effect, return_value=favorites
)
type(doorbirdapi_mock).favorites = AsyncMock(
side_effect=favorites_side_effect,
return_value=favorites,
)
type(doorbirdapi_mock).change_favorite = AsyncMock(return_value=True)
type(doorbirdapi_mock).change_schedule = AsyncMock(
api_mock_type.change_favorite = AsyncMock(return_value=True)
api_mock_type.change_schedule = AsyncMock(
return_value=change_schedule or (True, 200)
)
type(doorbirdapi_mock).schedule = AsyncMock(return_value=schedule)
type(doorbirdapi_mock).energize_relay = AsyncMock(return_value=True)
type(doorbirdapi_mock).turn_light_on = AsyncMock(return_value=True)
type(doorbirdapi_mock).delete_favorite = AsyncMock(return_value=True)
type(doorbirdapi_mock).get_image = AsyncMock(return_value=b"image")
type(doorbirdapi_mock).doorbell_state = AsyncMock(
side_effect=mock_unauthorized_exception()
api_mock_type.schedule = AsyncMock(
return_value=schedule, side_effect=schedule_side_effect
)
api_mock_type.energize_relay = AsyncMock(return_value=True)
api_mock_type.turn_light_on = AsyncMock(return_value=True)
api_mock_type.delete_favorite = AsyncMock(return_value=True)
api_mock_type.get_image = AsyncMock(return_value=b"image")
api_mock_type.doorbell_state = AsyncMock(side_effect=mock_unauthorized_exception())
return doorbirdapi_mock

View file

@ -102,6 +102,7 @@ async def doorbird_mocker(
info: dict[str, Any] | None = None,
info_side_effect: Exception | None = None,
schedule: list[DoorBirdScheduleEntry] | None = None,
schedule_side_effect: Exception | None = None,
favorites: dict[str, dict[str, Any]] | None = None,
favorites_side_effect: Exception | None = None,
options: dict[str, Any] | None = None,
@ -118,6 +119,7 @@ async def doorbird_mocker(
info=info or doorbird_info,
info_side_effect=info_side_effect,
schedule=schedule or doorbird_schedule,
schedule_side_effect=schedule_side_effect,
favorites=favorites or doorbird_favorites,
favorites_side_effect=favorites_side_effect,
change_schedule=change_schedule,

View file

@ -56,6 +56,16 @@ async def test_http_favorites_request_fails(
assert doorbird_entry.entry.state is ConfigEntryState.SETUP_RETRY
async def test_http_schedule_api_missing(
doorbird_mocker: DoorbirdMockerType,
) -> None:
"""Test missing the schedule API is non-fatal as not all models support it."""
doorbird_entry = await doorbird_mocker(
schedule_side_effect=mock_not_found_exception()
)
assert doorbird_entry.entry.state is ConfigEntryState.LOADED
async def test_events_changed(
hass: HomeAssistant,
doorbird_mocker: DoorbirdMockerType,