mirror of
https://github.com/home-assistant/core.git
synced 2025-07-20 03:37:07 +00:00
Automatically configure HTTP auth type in ONVIF snapshots (#38729)
* Allow selection of HTTP auth type in ONVIF snapshots * Auto populate snapshot auth * Fix no auth case * Add missing return
This commit is contained in:
parent
c1b8497aaa
commit
a87fedc0af
@ -1,6 +1,9 @@
|
||||
"""The ONVIF integration."""
|
||||
import asyncio
|
||||
|
||||
import requests
|
||||
from requests.auth import HTTPDigestAuth
|
||||
from urllib3.exceptions import ReadTimeoutError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.ffmpeg import CONF_EXTRA_ARGUMENTS
|
||||
@ -12,6 +15,8 @@ from homeassistant.const import (
|
||||
CONF_PORT,
|
||||
CONF_USERNAME,
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
HTTP_BASIC_AUTHENTICATION,
|
||||
HTTP_DIGEST_AUTHENTICATION,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
@ -19,6 +24,7 @@ from homeassistant.helpers import config_per_platform
|
||||
|
||||
from .const import (
|
||||
CONF_RTSP_TRANSPORT,
|
||||
CONF_SNAPSHOT_AUTH,
|
||||
DEFAULT_ARGUMENTS,
|
||||
DEFAULT_NAME,
|
||||
DEFAULT_PASSWORD,
|
||||
@ -76,6 +82,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||
if not device.available:
|
||||
raise ConfigEntryNotReady()
|
||||
|
||||
if not entry.data.get(CONF_SNAPSHOT_AUTH):
|
||||
await async_populate_snapshot_auth(hass, device, entry)
|
||||
|
||||
hass.data[DOMAIN][entry.unique_id] = device
|
||||
|
||||
platforms = ["camera"]
|
||||
@ -113,6 +122,39 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||
)
|
||||
|
||||
|
||||
async def _get_snapshot_auth(hass, device, entry):
|
||||
if not (device.username and device.password):
|
||||
return HTTP_DIGEST_AUTHENTICATION
|
||||
|
||||
snapshot_uri = await device.async_get_snapshot_uri(device.profiles[0])
|
||||
auth = HTTPDigestAuth(device.username, device.password)
|
||||
|
||||
def _get():
|
||||
# so we can handle keyword arguments
|
||||
return requests.get(snapshot_uri, timeout=1, auth=auth)
|
||||
|
||||
try:
|
||||
response = await hass.async_add_executor_job(_get)
|
||||
|
||||
if response.status_code == 401:
|
||||
return HTTP_BASIC_AUTHENTICATION
|
||||
|
||||
return HTTP_DIGEST_AUTHENTICATION
|
||||
except requests.exceptions.Timeout:
|
||||
return HTTP_BASIC_AUTHENTICATION
|
||||
except requests.exceptions.ConnectionError as error:
|
||||
if isinstance(error.args[0], ReadTimeoutError):
|
||||
return HTTP_BASIC_AUTHENTICATION
|
||||
return HTTP_DIGEST_AUTHENTICATION
|
||||
|
||||
|
||||
async def async_populate_snapshot_auth(hass, device, entry):
|
||||
"""Check if digest auth for snapshots is possible."""
|
||||
auth = await _get_snapshot_auth(hass, device, entry)
|
||||
new_data = {**entry.data, CONF_SNAPSHOT_AUTH: auth}
|
||||
hass.config_entries.async_update_entry(entry, data=new_data)
|
||||
|
||||
|
||||
async def async_populate_options(hass, entry):
|
||||
"""Populate default options for device."""
|
||||
options = {
|
||||
|
@ -4,11 +4,12 @@ import asyncio
|
||||
from haffmpeg.camera import CameraMjpeg
|
||||
from haffmpeg.tools import IMAGE_JPEG, ImageFrame
|
||||
import requests
|
||||
from requests.auth import HTTPDigestAuth
|
||||
from requests.auth import HTTPBasicAuth, HTTPDigestAuth
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.camera import SUPPORT_STREAM, Camera
|
||||
from homeassistant.components.ffmpeg import CONF_EXTRA_ARGUMENTS, DATA_FFMPEG
|
||||
from homeassistant.const import HTTP_BASIC_AUTHENTICATION
|
||||
from homeassistant.helpers import config_validation as cv, entity_platform
|
||||
from homeassistant.helpers.aiohttp_client import async_aiohttp_proxy_stream
|
||||
|
||||
@ -24,6 +25,7 @@ from .const import (
|
||||
ATTR_TILT,
|
||||
ATTR_ZOOM,
|
||||
CONF_RTSP_TRANSPORT,
|
||||
CONF_SNAPSHOT_AUTH,
|
||||
CONTINUOUS_MOVE,
|
||||
DIR_DOWN,
|
||||
DIR_LEFT,
|
||||
@ -79,6 +81,10 @@ class ONVIFCameraEntity(ONVIFBaseEntity, Camera):
|
||||
self.stream_options[CONF_RTSP_TRANSPORT] = device.config_entry.options.get(
|
||||
CONF_RTSP_TRANSPORT
|
||||
)
|
||||
self._basic_auth = (
|
||||
device.config_entry.data.get(CONF_SNAPSHOT_AUTH)
|
||||
== HTTP_BASIC_AUTHENTICATION
|
||||
)
|
||||
self._stream_uri = None
|
||||
self._snapshot_uri = None
|
||||
|
||||
@ -115,6 +121,9 @@ class ONVIFCameraEntity(ONVIFBaseEntity, Camera):
|
||||
if self.device.capabilities.snapshot:
|
||||
auth = None
|
||||
if self.device.username and self.device.password:
|
||||
if self._basic_auth:
|
||||
auth = HTTPBasicAuth(self.device.username, self.device.password)
|
||||
else:
|
||||
auth = HTTPDigestAuth(self.device.username, self.device.password)
|
||||
|
||||
def fetch():
|
||||
|
@ -13,6 +13,7 @@ DEFAULT_ARGUMENTS = "-pred 1"
|
||||
|
||||
CONF_DEVICE_ID = "deviceid"
|
||||
CONF_RTSP_TRANSPORT = "rtsp_transport"
|
||||
CONF_SNAPSHOT_AUTH = "snapshot_auth"
|
||||
|
||||
RTSP_TRANS_PROTOCOLS = ["tcp", "udp", "udp_multicast", "http"]
|
||||
|
||||
|
@ -13,8 +13,8 @@
|
||||
"step": {
|
||||
"auth": {
|
||||
"data": {
|
||||
"password": "Password",
|
||||
"username": "Username"
|
||||
"password": "[%key:common::config_flow::data::password%]",
|
||||
"username": "[%key:common::config_flow::data::username%]"
|
||||
},
|
||||
"title": "Configure authentication"
|
||||
},
|
||||
@ -33,9 +33,9 @@
|
||||
},
|
||||
"manual_input": {
|
||||
"data": {
|
||||
"host": "Host",
|
||||
"host": "[%key:common::config_flow::data::host%]",
|
||||
"name": "Name",
|
||||
"port": "Port"
|
||||
"port": "[%key:common::config_flow::data::port%]"
|
||||
},
|
||||
"title": "Configure ONVIF device"
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user