diff --git a/homeassistant/components/onvif/__init__.py b/homeassistant/components/onvif/__init__.py index 2c96b79cbeb..a7c23064f64 100644 --- a/homeassistant/components/onvif/__init__.py +++ b/homeassistant/components/onvif/__init__.py @@ -1,5 +1,6 @@ """The ONVIF integration.""" import asyncio +from http import HTTPStatus import logging from httpx import RequestError @@ -56,7 +57,20 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: except ONVIFError as err: await device.device.close() raise ConfigEntryNotReady( - f"Could not setup camera {device.device.host}:{device.device.port}: {err}" + f"Could not setup camera {device.device.host}:{device.device.port}: {stringify_onvif_error(err)}" + ) from err + except TransportError as err: + await device.device.close() + stringified_onvif_error = stringify_onvif_error(err) + if err.status_code in ( + HTTPStatus.UNAUTHORIZED.value, + HTTPStatus.FORBIDDEN.value, + ): + raise ConfigEntryAuthFailed( + f"Auth Failed: {stringified_onvif_error}" + ) from err + raise ConfigEntryNotReady( + f"Could not setup camera {device.device.host}:{device.device.port}: {stringified_onvif_error}" ) from err except asyncio.CancelledError as err: # After https://github.com/agronholm/anyio/issues/374 is resolved diff --git a/homeassistant/components/onvif/config_flow.py b/homeassistant/components/onvif/config_flow.py index 27f279266dd..ca447c71b84 100644 --- a/homeassistant/components/onvif/config_flow.py +++ b/homeassistant/components/onvif/config_flow.py @@ -142,10 +142,14 @@ class OnvifFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): hass.async_create_task(hass.config_entries.async_reload(entry_id)) return self.async_abort(reason="reauth_successful") + username = (user_input or {}).get(CONF_USERNAME) or entry.data[CONF_USERNAME] return self.async_show_form( step_id="reauth_confirm", data_schema=vol.Schema( - {vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str} + { + vol.Required(CONF_USERNAME, default=username): str, + vol.Required(CONF_PASSWORD): str, + } ), errors=errors, description_placeholders=description_placeholders, diff --git a/homeassistant/components/onvif/strings.json b/homeassistant/components/onvif/strings.json index 55413e4bf6c..3e9db0b3c7e 100644 --- a/homeassistant/components/onvif/strings.json +++ b/homeassistant/components/onvif/strings.json @@ -47,6 +47,7 @@ }, "reauth_confirm": { "title": "Reauthenticate the ONVIF device", + "description": "Some devices will reject authentication if the time is out of sync by more than 5 seconds. If authentication is unsuccessful, verify the time on the device is correct and try again.", "data": { "username": "[%key:common::config_flow::data::username%]", "password": "[%key:common::config_flow::data::password%]" diff --git a/tests/components/onvif/test_config_flow.py b/tests/components/onvif/test_config_flow.py index 21ef1cf3fc2..8187a427be9 100644 --- a/tests/components/onvif/test_config_flow.py +++ b/tests/components/onvif/test_config_flow.py @@ -5,7 +5,7 @@ from homeassistant import config_entries, data_entry_flow from homeassistant.components import dhcp from homeassistant.components.onvif import DOMAIN, config_flow from homeassistant.config_entries import SOURCE_DHCP -from homeassistant.const import CONF_HOST +from homeassistant.const import CONF_HOST, CONF_USERNAME from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType from homeassistant.helpers import device_registry as dr @@ -710,6 +710,14 @@ async def test_discovered_by_dhcp_does_not_update_if_no_matching_entry( assert result["reason"] == "no_devices_found" +def _get_schema_default(schema, key_name): + """Iterate schema to find a key.""" + for schema_key in schema: + if schema_key == key_name: + return schema_key.default() + raise KeyError(f"{key_name} not found in schema") + + async def test_form_reauth(hass: HomeAssistant) -> None: """Test reauthenticate.""" entry, _, _ = await setup_onvif_integration(hass) @@ -721,6 +729,10 @@ async def test_form_reauth(hass: HomeAssistant) -> None: ) assert result["type"] == FlowResultType.FORM assert result["step_id"] == "reauth_confirm" + assert ( + _get_schema_default(result["data_schema"].schema, CONF_USERNAME) + == entry.data[CONF_USERNAME] + ) with patch( "homeassistant.components.onvif.config_flow.get_device"