mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 22:27:07 +00:00
Add visual image preview during generic camera options flow (#80392)
Co-authored-by: Dave T <davet2001@users.noreply.github.com>
This commit is contained in:
parent
6b1f503a79
commit
e5716efa9c
@ -394,8 +394,7 @@ class GenericOptionsFlowHandler(OptionsFlow):
|
|||||||
def __init__(self, config_entry: ConfigEntry) -> None:
|
def __init__(self, config_entry: ConfigEntry) -> None:
|
||||||
"""Initialize Generic IP Camera options flow."""
|
"""Initialize Generic IP Camera options flow."""
|
||||||
self.config_entry = config_entry
|
self.config_entry = config_entry
|
||||||
self.cached_user_input: dict[str, Any] = {}
|
self.user_input: dict[str, Any] = {}
|
||||||
self.cached_title = ""
|
|
||||||
|
|
||||||
async def async_step_init(
|
async def async_step_init(
|
||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, Any] | None = None
|
||||||
@ -410,9 +409,7 @@ class GenericOptionsFlowHandler(OptionsFlow):
|
|||||||
)
|
)
|
||||||
errors = errors | await async_test_stream(hass, user_input)
|
errors = errors | await async_test_stream(hass, user_input)
|
||||||
still_url = user_input.get(CONF_STILL_IMAGE_URL)
|
still_url = user_input.get(CONF_STILL_IMAGE_URL)
|
||||||
stream_url = user_input.get(CONF_STREAM_SOURCE)
|
|
||||||
if not errors:
|
if not errors:
|
||||||
title = slug(hass, still_url) or slug(hass, stream_url) or DEFAULT_NAME
|
|
||||||
if still_url is None:
|
if still_url is None:
|
||||||
# If user didn't specify a still image URL,
|
# If user didn't specify a still image URL,
|
||||||
# The automatically generated still image that stream generates
|
# The automatically generated still image that stream generates
|
||||||
@ -438,10 +435,10 @@ class GenericOptionsFlowHandler(OptionsFlow):
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
return self.async_create_entry(
|
self.user_input = data
|
||||||
title=title,
|
# temporary preview for user to check the image
|
||||||
data=data,
|
self.context["preview_cam"] = data
|
||||||
)
|
return await self.async_step_confirm_still()
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="init",
|
step_id="init",
|
||||||
data_schema=build_schema(
|
data_schema=build_schema(
|
||||||
@ -452,6 +449,30 @@ class GenericOptionsFlowHandler(OptionsFlow):
|
|||||||
errors=errors,
|
errors=errors,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def async_step_confirm_still(
|
||||||
|
self, user_input: dict[str, Any] | None = None
|
||||||
|
) -> FlowResult:
|
||||||
|
"""Handle user clicking confirm after still preview."""
|
||||||
|
if user_input:
|
||||||
|
if not user_input.get(CONF_CONFIRMED_OK):
|
||||||
|
return await self.async_step_init()
|
||||||
|
return self.async_create_entry(
|
||||||
|
title=self.config_entry.title,
|
||||||
|
data=self.user_input,
|
||||||
|
)
|
||||||
|
register_preview(self.hass)
|
||||||
|
preview_url = f"/api/generic/preview_flow_image/{self.flow_id}?t={datetime.now().isoformat()}"
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="confirm_still",
|
||||||
|
data_schema=vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_CONFIRMED_OK, default=False): bool,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
description_placeholders={"preview_url": preview_url},
|
||||||
|
errors=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CameraImagePreview(HomeAssistantView):
|
class CameraImagePreview(HomeAssistantView):
|
||||||
"""Camera view to temporarily serve an image."""
|
"""Camera view to temporarily serve an image."""
|
||||||
@ -468,8 +489,12 @@ class CameraImagePreview(HomeAssistantView):
|
|||||||
"""Start a GET request."""
|
"""Start a GET request."""
|
||||||
_LOGGER.debug("processing GET request for flow_id=%s", flow_id)
|
_LOGGER.debug("processing GET request for flow_id=%s", flow_id)
|
||||||
try:
|
try:
|
||||||
flow: FlowResult = self.hass.config_entries.flow.async_get(flow_id)
|
flow = self.hass.config_entries.flow.async_get(flow_id)
|
||||||
|
except UnknownFlow:
|
||||||
|
try:
|
||||||
|
flow = self.hass.config_entries.options.async_get(flow_id)
|
||||||
except UnknownFlow as exc:
|
except UnknownFlow as exc:
|
||||||
|
_LOGGER.warning("Unknown flow while getting image preview")
|
||||||
raise web.HTTPNotFound() from exc
|
raise web.HTTPNotFound() from exc
|
||||||
user_input = flow["context"]["preview_cam"]
|
user_input = flow["context"]["preview_cam"]
|
||||||
camera = GenericCamera(self.hass, user_input, flow_id, "preview")
|
camera = GenericCamera(self.hass, user_input, flow_id, "preview")
|
||||||
|
@ -73,6 +73,13 @@
|
|||||||
"data": {
|
"data": {
|
||||||
"content_type": "[%key:component::generic::config::step::content_type::data::content_type%]"
|
"content_type": "[%key:component::generic::config::step::content_type::data::content_type%]"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"confirm_still": {
|
||||||
|
"title": "[%key:component::generic::config::step::user_confirm_still::title%]",
|
||||||
|
"description": "[%key:component::generic::config::step::user_confirm_still::description%]",
|
||||||
|
"data": {
|
||||||
|
"confirmed_ok": "[%key:component::generic::config::step::user_confirm_still::data::confirmed_ok%]"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
|
@ -596,7 +596,13 @@ async def test_options_template_error(hass, fakeimgbytes_png, mock_create_stream
|
|||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input=data,
|
user_input=data,
|
||||||
)
|
)
|
||||||
assert result2["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
|
assert result2["type"] == data_entry_flow.FlowResultType.FORM
|
||||||
|
assert result2["step_id"] == "confirm_still"
|
||||||
|
|
||||||
|
result2a = await hass.config_entries.options.async_configure(
|
||||||
|
result2["flow_id"], user_input={CONF_CONFIRMED_OK: True}
|
||||||
|
)
|
||||||
|
assert result2a["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
|
||||||
|
|
||||||
result3 = await hass.config_entries.options.async_init(mock_entry.entry_id)
|
result3 = await hass.config_entries.options.async_init(mock_entry.entry_id)
|
||||||
assert result3["type"] == data_entry_flow.FlowResultType.FORM
|
assert result3["type"] == data_entry_flow.FlowResultType.FORM
|
||||||
@ -681,10 +687,16 @@ async def test_options_only_stream(hass, fakeimgbytes_png, mock_create_stream):
|
|||||||
|
|
||||||
# try updating the config options
|
# try updating the config options
|
||||||
with mock_create_stream:
|
with mock_create_stream:
|
||||||
result3 = await hass.config_entries.options.async_configure(
|
result2 = await hass.config_entries.options.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input=data,
|
user_input=data,
|
||||||
)
|
)
|
||||||
|
assert result2["type"] == data_entry_flow.FlowResultType.FORM
|
||||||
|
assert result2["step_id"] == "confirm_still"
|
||||||
|
|
||||||
|
result3 = await hass.config_entries.options.async_configure(
|
||||||
|
result2["flow_id"], user_input={CONF_CONFIRMED_OK: True}
|
||||||
|
)
|
||||||
assert result3["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
|
assert result3["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
|
||||||
assert result3["data"][CONF_CONTENT_TYPE] == "image/jpeg"
|
assert result3["data"][CONF_CONTENT_TYPE] == "image/jpeg"
|
||||||
|
|
||||||
@ -809,4 +821,24 @@ async def test_use_wallclock_as_timestamps_option(
|
|||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input={CONF_USE_WALLCLOCK_AS_TIMESTAMPS: True, **TESTDATA},
|
user_input={CONF_USE_WALLCLOCK_AS_TIMESTAMPS: True, **TESTDATA},
|
||||||
)
|
)
|
||||||
assert result2["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
|
assert result2["type"] == data_entry_flow.FlowResultType.FORM
|
||||||
|
# Test what happens if user rejects the preview
|
||||||
|
result3 = await hass.config_entries.options.async_configure(
|
||||||
|
result2["flow_id"], user_input={CONF_CONFIRMED_OK: False}
|
||||||
|
)
|
||||||
|
assert result3["type"] == data_entry_flow.FlowResultType.FORM
|
||||||
|
assert result3["step_id"] == "init"
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.generic.async_setup_entry", return_value=True
|
||||||
|
), mock_create_stream:
|
||||||
|
result4 = await hass.config_entries.options.async_configure(
|
||||||
|
result3["flow_id"],
|
||||||
|
user_input={CONF_USE_WALLCLOCK_AS_TIMESTAMPS: True, **TESTDATA},
|
||||||
|
)
|
||||||
|
assert result4["type"] == data_entry_flow.FlowResultType.FORM
|
||||||
|
assert result4["step_id"] == "confirm_still"
|
||||||
|
result5 = await hass.config_entries.options.async_configure(
|
||||||
|
result4["flow_id"],
|
||||||
|
user_input={CONF_CONFIRMED_OK: True},
|
||||||
|
)
|
||||||
|
assert result5["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
|
||||||
|
Loading…
x
Reference in New Issue
Block a user