1 """The ONVIF integration."""
4 from contextlib
import suppress
5 from http
import HTTPStatus
8 from httpx
import RequestError
9 from onvif.exceptions
import ONVIFError
10 from onvif.util
import is_auth_error, stringify_onvif_error
11 from zeep.exceptions
import Fault, TransportError
17 EVENT_HOMEASSISTANT_STOP,
18 HTTP_BASIC_AUTHENTICATION,
19 HTTP_DIGEST_AUTHENTICATION,
29 DEFAULT_ENABLE_WEBHOOKS,
32 from .device
import ONVIFDevice
34 LOGGER = logging.getLogger(__name__)
38 """Set up ONVIF from a config entry."""
39 if DOMAIN
not in hass.data:
40 hass.data[DOMAIN] = {}
48 await device.async_setup()
49 if not entry.data.get(CONF_SNAPSHOT_AUTH):
51 except RequestError
as err:
52 await device.device.close()
54 f
"Could not connect to camera {device.device.host}:{device.device.port}: {err}"
57 await device.device.close()
60 f
"Auth Failed: {stringify_onvif_error(err)}"
63 f
"Could not connect to camera: {stringify_onvif_error(err)}"
65 except ONVIFError
as err:
66 await device.device.close()
68 f
"Could not setup camera {device.device.host}:{device.device.port}: {stringify_onvif_error(err)}"
70 except TransportError
as err:
71 await device.device.close()
73 if err.status_code
in (
74 HTTPStatus.UNAUTHORIZED.value,
75 HTTPStatus.FORBIDDEN.value,
78 f
"Auth Failed: {stringified_onvif_error}"
81 f
"Could not setup camera {device.device.host}:{device.device.port}: {stringified_onvif_error}"
83 except asyncio.CancelledError
as err:
86 await device.device.close()
89 if not device.available:
90 raise ConfigEntryNotReady
92 hass.data[DOMAIN][entry.unique_id] = device
94 device.platforms = [Platform.BUTTON, Platform.CAMERA]
96 if device.capabilities.events:
97 device.platforms += [Platform.BINARY_SENSOR, Platform.SENSOR]
99 if device.capabilities.imaging:
100 device.platforms += [Platform.SWITCH]
102 await hass.config_entries.async_forward_entry_setups(entry, device.platforms)
104 entry.async_on_unload(
105 hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, device.async_stop)
112 """Unload a config entry."""
114 device: ONVIFDevice = hass.data[DOMAIN][entry.unique_id]
116 if device.capabilities.events
and device.events.started:
118 await device.events.async_stop()
119 except (ONVIFError, Fault, RequestError, TransportError):
120 LOGGER.warning(
"Error while stopping events: %s", device.name)
122 return await hass.config_entries.async_unload_platforms(entry, device.platforms)
126 """Determine auth type for snapshots."""
127 if not device.capabilities.snapshot:
130 for basic_auth
in (
False,
True):
131 method = HTTP_BASIC_AUTHENTICATION
if basic_auth
else HTTP_DIGEST_AUTHENTICATION
132 with suppress(ONVIFError):
133 if await device.device.get_snapshot(device.profiles[0].token, basic_auth):
140 hass: HomeAssistant, device: ONVIFDevice, entry: ConfigEntry
142 """Check if digest auth for snapshots is possible."""
144 hass.config_entries.async_update_entry(
145 entry, data={**entry.data, CONF_SNAPSHOT_AUTH: auth}
150 """Populate default options for device."""
152 CONF_EXTRA_ARGUMENTS: DEFAULT_ARGUMENTS,
153 CONF_RTSP_TRANSPORT: next(iter(RTSP_TRANSPORTS)),
154 CONF_ENABLE_WEBHOOKS: DEFAULT_ENABLE_WEBHOOKS,
157 hass.config_entries.async_update_entry(entry, options=options)
str stringify_onvif_error(Exception error)
bool is_auth_error(Exception error)
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
None async_populate_options(HomeAssistant hass, ConfigEntry entry)
None async_populate_snapshot_auth(HomeAssistant hass, ONVIFDevice device, ConfigEntry entry)
str|None _get_snapshot_auth(ONVIFDevice device)