diff --git a/homeassistant/components/doorbird/device.py b/homeassistant/components/doorbird/device.py index 866251f3d28..7cd45487464 100644 --- a/homeassistant/components/doorbird/device.py +++ b/homeassistant/components/doorbird/device.py @@ -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 diff --git a/tests/components/doorbird/__init__.py b/tests/components/doorbird/__init__.py index 41def92f121..2d517dfcefe 100644 --- a/tests/components/doorbird/__init__.py +++ b/tests/components/doorbird/__init__.py @@ -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 diff --git a/tests/components/doorbird/conftest.py b/tests/components/doorbird/conftest.py index 59ead250293..2e367e4e1d8 100644 --- a/tests/components/doorbird/conftest.py +++ b/tests/components/doorbird/conftest.py @@ -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, diff --git a/tests/components/doorbird/test_init.py b/tests/components/doorbird/test_init.py index fb8bad2fb46..31266c4acf0 100644 --- a/tests/components/doorbird/test_init.py +++ b/tests/components/doorbird/test_init.py @@ -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,