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:
Dave T 2022-10-25 09:03:19 +01:00 committed by GitHub
parent 6b1f503a79
commit e5716efa9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 78 additions and 14 deletions

View File

@ -394,8 +394,7 @@ class GenericOptionsFlowHandler(OptionsFlow):
def __init__(self, config_entry: ConfigEntry) -> None:
"""Initialize Generic IP Camera options flow."""
self.config_entry = config_entry
self.cached_user_input: dict[str, Any] = {}
self.cached_title = ""
self.user_input: dict[str, Any] = {}
async def async_step_init(
self, user_input: dict[str, Any] | None = None
@ -410,9 +409,7 @@ class GenericOptionsFlowHandler(OptionsFlow):
)
errors = errors | await async_test_stream(hass, user_input)
still_url = user_input.get(CONF_STILL_IMAGE_URL)
stream_url = user_input.get(CONF_STREAM_SOURCE)
if not errors:
title = slug(hass, still_url) or slug(hass, stream_url) or DEFAULT_NAME
if still_url is None:
# If user didn't specify a still image URL,
# The automatically generated still image that stream generates
@ -438,10 +435,10 @@ class GenericOptionsFlowHandler(OptionsFlow):
),
),
}
return self.async_create_entry(
title=title,
data=data,
)
self.user_input = data
# temporary preview for user to check the image
self.context["preview_cam"] = data
return await self.async_step_confirm_still()
return self.async_show_form(
step_id="init",
data_schema=build_schema(
@ -452,6 +449,30 @@ class GenericOptionsFlowHandler(OptionsFlow):
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):
"""Camera view to temporarily serve an image."""
@ -468,9 +489,13 @@ class CameraImagePreview(HomeAssistantView):
"""Start a GET request."""
_LOGGER.debug("processing GET request for flow_id=%s", flow_id)
try:
flow: FlowResult = self.hass.config_entries.flow.async_get(flow_id)
except UnknownFlow as exc:
raise web.HTTPNotFound() from exc
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:
_LOGGER.warning("Unknown flow while getting image preview")
raise web.HTTPNotFound() from exc
user_input = flow["context"]["preview_cam"]
camera = GenericCamera(self.hass, user_input, flow_id, "preview")
if not camera.is_on:

View File

@ -73,6 +73,13 @@
"data": {
"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": {

View File

@ -596,7 +596,13 @@ async def test_options_template_error(hass, fakeimgbytes_png, mock_create_stream
result["flow_id"],
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)
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
with mock_create_stream:
result3 = await hass.config_entries.options.async_configure(
result2 = await hass.config_entries.options.async_configure(
result["flow_id"],
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["data"][CONF_CONTENT_TYPE] == "image/jpeg"
@ -809,4 +821,24 @@ async def test_use_wallclock_as_timestamps_option(
result["flow_id"],
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