mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 12:17:07 +00:00
Add Supervisor discovery to motionEye (#50901)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
18e6ae8750
commit
19c505c0f0
@ -32,6 +32,7 @@ class MotionEyeConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for motionEye."""
|
||||
|
||||
VERSION = 1
|
||||
_hassio_discovery: dict[str, Any] | None = None
|
||||
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
@ -42,13 +43,18 @@ class MotionEyeConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
user_input: dict[str, Any], errors: dict[str, str] | None = None
|
||||
) -> FlowResult:
|
||||
"""Show the form to the user."""
|
||||
url_schema: dict[vol.Required, type[str]] = {}
|
||||
if not self._hassio_discovery:
|
||||
# Only ask for URL when not discovered
|
||||
url_schema[
|
||||
vol.Required(CONF_URL, default=user_input.get(CONF_URL, ""))
|
||||
] = str
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="user",
|
||||
data_schema=vol.Schema(
|
||||
{
|
||||
vol.Required(
|
||||
CONF_URL, default=user_input.get(CONF_URL, "")
|
||||
): str,
|
||||
**url_schema,
|
||||
vol.Optional(
|
||||
CONF_ADMIN_USERNAME,
|
||||
default=user_input.get(CONF_ADMIN_USERNAME),
|
||||
@ -81,6 +87,10 @@ class MotionEyeConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
cast(Dict[str, Any], reauth_entry.data) if reauth_entry else {}
|
||||
)
|
||||
|
||||
if self._hassio_discovery:
|
||||
# In case of Supervisor discovery, use pushed URL
|
||||
user_input[CONF_URL] = self._hassio_discovery[CONF_URL]
|
||||
|
||||
try:
|
||||
# Cannot use cv.url validation in the schema itself, so
|
||||
# apply extra validation here.
|
||||
@ -123,8 +133,12 @@ class MotionEyeConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
# at least prevent entries with the same motionEye URL.
|
||||
self._async_abort_entries_match({CONF_URL: user_input[CONF_URL]})
|
||||
|
||||
title = user_input[CONF_URL]
|
||||
if self._hassio_discovery:
|
||||
title = "Add-on"
|
||||
|
||||
return self.async_create_entry(
|
||||
title=f"{user_input[CONF_URL]}",
|
||||
title=title,
|
||||
data=user_input,
|
||||
)
|
||||
|
||||
@ -134,3 +148,22 @@ class MotionEyeConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
) -> FlowResult:
|
||||
"""Handle a reauthentication flow."""
|
||||
return await self.async_step_user(config_data)
|
||||
|
||||
async def async_step_hassio(self, discovery_info: dict[str, Any]) -> FlowResult:
|
||||
"""Handle Supervisor discovery."""
|
||||
self._hassio_discovery = discovery_info
|
||||
await self._async_handle_discovery_without_unique_id()
|
||||
|
||||
return await self.async_step_hassio_confirm()
|
||||
|
||||
async def async_step_hassio_confirm(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Confirm Supervisor discovery."""
|
||||
if user_input is None and self._hassio_discovery is not None:
|
||||
return self.async_show_form(
|
||||
step_id="hassio_confirm",
|
||||
description_placeholders={"addon": self._hassio_discovery["addon"]},
|
||||
)
|
||||
|
||||
return await self.async_step_user()
|
||||
|
@ -9,6 +9,10 @@
|
||||
"surveillance_username": "Surveillance [%key:common::config_flow::data::username%]",
|
||||
"surveillance_password": "Surveillance [%key:common::config_flow::data::password%]"
|
||||
}
|
||||
},
|
||||
"hassio_confirm": {
|
||||
"title": "motionEye via Home Assistant add-on",
|
||||
"description": "Do you want to configure Home Assistant to connect to the motionEye service provided by the add-on: {addon}?"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
|
@ -11,6 +11,10 @@
|
||||
"unknown": "Unexpected error"
|
||||
},
|
||||
"step": {
|
||||
"hassio_confirm": {
|
||||
"description": "Do you want to configure Home Assistant to connect to the motionEye service provided by the add-on: {addon}?",
|
||||
"title": "motionEye via Home Assistant add-on"
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"admin_password": "Admin Password",
|
||||
|
@ -69,6 +69,58 @@ async def test_user_success(hass: HomeAssistant) -> None:
|
||||
assert mock_client.async_client_close.called
|
||||
|
||||
|
||||
async def test_hassio_success(hass: HomeAssistant) -> None:
|
||||
"""Test successful Supervisor flow."""
|
||||
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
data={"addon": "motionEye", "url": TEST_URL},
|
||||
context={"source": config_entries.SOURCE_HASSIO},
|
||||
)
|
||||
|
||||
assert result.get("type") == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result.get("step_id") == "hassio_confirm"
|
||||
assert result.get("description_placeholders") == {"addon": "motionEye"}
|
||||
assert "flow_id" in result
|
||||
|
||||
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
assert result2.get("type") == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result2.get("step_id") == "user"
|
||||
assert "flow_id" in result2
|
||||
|
||||
mock_client = create_mock_motioneye_client()
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.motioneye.MotionEyeClient",
|
||||
return_value=mock_client,
|
||||
), patch(
|
||||
"homeassistant.components.motioneye.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry:
|
||||
result3 = await hass.config_entries.flow.async_configure(
|
||||
result2["flow_id"],
|
||||
{
|
||||
CONF_ADMIN_USERNAME: "admin-username",
|
||||
CONF_ADMIN_PASSWORD: "admin-password",
|
||||
CONF_SURVEILLANCE_USERNAME: "surveillance-username",
|
||||
CONF_SURVEILLANCE_PASSWORD: "surveillance-password",
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result3.get("type") == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result3.get("title") == "Add-on"
|
||||
assert result3.get("data") == {
|
||||
CONF_URL: TEST_URL,
|
||||
CONF_ADMIN_USERNAME: "admin-username",
|
||||
CONF_ADMIN_PASSWORD: "admin-password",
|
||||
CONF_SURVEILLANCE_USERNAME: "surveillance-username",
|
||||
CONF_SURVEILLANCE_PASSWORD: "surveillance-password",
|
||||
}
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
assert mock_client.async_client_close.called
|
||||
|
||||
|
||||
async def test_user_invalid_auth(hass: HomeAssistant) -> None:
|
||||
"""Test invalid auth is handled correctly."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
@ -287,3 +339,95 @@ async def test_duplicate(hass: HomeAssistant) -> None:
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
assert mock_client.async_client_close.called
|
||||
|
||||
|
||||
async def test_hassio_already_configured(hass: HomeAssistant) -> None:
|
||||
"""Test we don't discover when already configured."""
|
||||
MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_URL: TEST_URL},
|
||||
).add_to_hass(hass)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
data={"addon": "motionEye", "url": TEST_URL},
|
||||
context={"source": config_entries.SOURCE_HASSIO},
|
||||
)
|
||||
assert result.get("type") == data_entry_flow.RESULT_TYPE_ABORT
|
||||
assert result.get("reason") == "already_configured"
|
||||
|
||||
|
||||
async def test_hassio_ignored(hass: HomeAssistant) -> None:
|
||||
"""Test Supervisor discovered instance can be ignored."""
|
||||
MockConfigEntry(domain=DOMAIN, source=config_entries.SOURCE_IGNORE).add_to_hass(
|
||||
hass
|
||||
)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
data={"addon": "motionEye", "url": TEST_URL},
|
||||
context={"source": config_entries.SOURCE_HASSIO},
|
||||
)
|
||||
assert result.get("type") == data_entry_flow.RESULT_TYPE_ABORT
|
||||
assert result.get("reason") == "already_configured"
|
||||
|
||||
|
||||
async def test_hassio_abort_if_already_in_progress(hass: HomeAssistant) -> None:
|
||||
"""Test Supervisor discovered flow aborts if user flow in progress."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result.get("type") == data_entry_flow.RESULT_TYPE_FORM
|
||||
|
||||
result2 = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
data={"addon": "motionEye", "url": TEST_URL},
|
||||
context={"source": config_entries.SOURCE_HASSIO},
|
||||
)
|
||||
assert result2.get("type") == data_entry_flow.RESULT_TYPE_ABORT
|
||||
assert result2.get("reason") == "already_in_progress"
|
||||
|
||||
|
||||
async def test_hassio_clean_up_on_user_flow(hass: HomeAssistant) -> None:
|
||||
"""Test Supervisor discovered flow is clean up when doing user flow."""
|
||||
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
data={"addon": "motionEye", "url": TEST_URL},
|
||||
context={"source": config_entries.SOURCE_HASSIO},
|
||||
)
|
||||
assert result.get("type") == data_entry_flow.RESULT_TYPE_FORM
|
||||
|
||||
result2 = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result2.get("type") == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert "flow_id" in result2
|
||||
|
||||
mock_client = create_mock_motioneye_client()
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.motioneye.MotionEyeClient",
|
||||
return_value=mock_client,
|
||||
), patch(
|
||||
"homeassistant.components.motioneye.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry:
|
||||
result3 = await hass.config_entries.flow.async_configure(
|
||||
result2["flow_id"],
|
||||
{
|
||||
CONF_URL: TEST_URL,
|
||||
CONF_ADMIN_USERNAME: "admin-username",
|
||||
CONF_ADMIN_PASSWORD: "admin-password",
|
||||
CONF_SURVEILLANCE_USERNAME: "surveillance-username",
|
||||
CONF_SURVEILLANCE_PASSWORD: "surveillance-password",
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result3.get("type") == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
flows = hass.config_entries.flow.async_progress()
|
||||
assert len(flows) == 0
|
||||
|
Loading…
x
Reference in New Issue
Block a user