From 324df197d196fe9d484e5e5b5bdbc0ac4af70934 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 1 May 2023 11:33:52 -0500 Subject: [PATCH] Avoid starting ONVIF PullPoint if the camera reports its unsupported (#92333) --- homeassistant/components/onvif/device.py | 23 +++++++++++++++++--- homeassistant/components/onvif/event.py | 8 ++++--- homeassistant/components/onvif/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/onvif/device.py b/homeassistant/components/onvif/device.py index 57478031165..adb6fa89059 100644 --- a/homeassistant/components/onvif/device.py +++ b/homeassistant/components/onvif/device.py @@ -6,6 +6,7 @@ from contextlib import suppress import datetime as dt import os import time +from typing import Any from httpx import RequestError import onvif @@ -55,6 +56,7 @@ class ONVIFDevice: self.info: DeviceInfo = DeviceInfo() self.capabilities: Capabilities = Capabilities() + self.onvif_capabilities: dict[str, Any] | None = None self.profiles: list[Profile] = [] self.max_resolution: int = 0 self.platforms: list[Platform] = [] @@ -98,6 +100,10 @@ class ONVIFDevice: # Get all device info await self.device.update_xaddrs() + + # Get device capabilities + self.onvif_capabilities = await self.device.get_capabilities() + await self.async_check_date_and_time() # Create event manager @@ -107,8 +113,9 @@ class ONVIFDevice: # Fetch basic device info and capabilities self.info = await self.async_get_device_info() LOGGER.debug("Camera %s info = %s", self.name, self.info) - self.capabilities = await self.async_get_capabilities() - LOGGER.debug("Camera %s capabilities = %s", self.name, self.capabilities) + + # Check profiles before capabilities since the camera may be slow to respond + # once the event manager is started in async_get_capabilities. self.profiles = await self.async_get_profiles() LOGGER.debug("Camera %s profiles = %s", self.name, self.profiles) @@ -116,6 +123,9 @@ class ONVIFDevice: if not self.profiles: raise ONVIFError("No camera profiles found") + self.capabilities = await self.async_get_capabilities() + LOGGER.debug("Camera %s capabilities = %s", self.name, self.capabilities) + if self.capabilities.ptz: self.device.create_ptz_service() @@ -299,7 +309,14 @@ class ONVIFDevice: events = False with suppress(*GET_CAPABILITIES_EXCEPTIONS, XMLParseError): - events = await self.events.async_start() + onvif_capabilities = self.onvif_capabilities or {} + pull_point_support = onvif_capabilities.get("Events", {}).get( + "WSPullPointSupport" + ) + LOGGER.debug("%s: WSPullPointSupport: %s", self.name, pull_point_support) + events = await self.events.async_start( + pull_point_support is not False, True + ) return Capabilities(snapshot, events, ptz, imaging) diff --git a/homeassistant/components/onvif/event.py b/homeassistant/components/onvif/event.py index a3b11fab196..4c2efabf61a 100644 --- a/homeassistant/components/onvif/event.py +++ b/homeassistant/components/onvif/event.py @@ -123,11 +123,13 @@ class EventManager: if not self._listeners: self.pullpoint_manager.async_cancel_pull_messages() - async def async_start(self) -> bool: + async def async_start(self, try_pullpoint: bool, try_webhook: bool) -> bool: """Start polling events.""" # Always start pull point first, since it will populate the event list - event_via_pull_point = await self.pullpoint_manager.async_start() - events_via_webhook = await self.webhook_manager.async_start() + event_via_pull_point = ( + try_pullpoint and await self.pullpoint_manager.async_start() + ) + events_via_webhook = try_webhook and await self.webhook_manager.async_start() return events_via_webhook or event_via_pull_point async def async_stop(self) -> None: diff --git a/homeassistant/components/onvif/manifest.json b/homeassistant/components/onvif/manifest.json index 41d5164452f..17e7f1f0f29 100644 --- a/homeassistant/components/onvif/manifest.json +++ b/homeassistant/components/onvif/manifest.json @@ -8,5 +8,5 @@ "documentation": "https://www.home-assistant.io/integrations/onvif", "iot_class": "local_push", "loggers": ["onvif", "wsdiscovery", "zeep"], - "requirements": ["onvif-zeep-async==1.3.0", "WSDiscovery==2.0.0"] + "requirements": ["onvif-zeep-async==1.3.1", "WSDiscovery==2.0.0"] } diff --git a/requirements_all.txt b/requirements_all.txt index be3c22bb762..77892485023 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1258,7 +1258,7 @@ ondilo==0.2.0 onkyo-eiscp==1.2.7 # homeassistant.components.onvif -onvif-zeep-async==1.3.0 +onvif-zeep-async==1.3.1 # homeassistant.components.opengarage open-garage==0.2.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index fd56a9e8f40..0429b82ae9e 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -945,7 +945,7 @@ omnilogic==0.4.5 ondilo==0.2.0 # homeassistant.components.onvif -onvif-zeep-async==1.3.0 +onvif-zeep-async==1.3.1 # homeassistant.components.opengarage open-garage==0.2.0