Add use_wallclock_as_timestamps option to generic (#71245)

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
uvjustin 2022-05-13 07:43:24 +08:00 committed by GitHub
parent a746d7c1d7
commit 7e49ae6410
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 67 additions and 4 deletions

View File

@ -37,6 +37,7 @@ from .const import (
CONF_RTSP_TRANSPORT,
CONF_STILL_IMAGE_URL,
CONF_STREAM_SOURCE,
CONF_USE_WALLCLOCK_AS_TIMESTAMPS,
DEFAULT_NAME,
FFMPEG_OPTION_MAP,
GET_IMAGE_TIMEOUT,
@ -160,6 +161,10 @@ class GenericCamera(Camera):
CONF_RTSP_TRANSPORT
]
self._auth = generate_auth(device_info)
if device_info.get(CONF_USE_WALLCLOCK_AS_TIMESTAMPS):
self.stream_options[
FFMPEG_OPTION_MAP[CONF_USE_WALLCLOCK_AS_TIMESTAMPS]
] = "1"
self._last_url = None
self._last_image = None

View File

@ -41,6 +41,7 @@ from .const import (
CONF_RTSP_TRANSPORT,
CONF_STILL_IMAGE_URL,
CONF_STREAM_SOURCE,
CONF_USE_WALLCLOCK_AS_TIMESTAMPS,
DEFAULT_NAME,
DOMAIN,
FFMPEG_OPTION_MAP,
@ -64,6 +65,7 @@ SUPPORTED_IMAGE_TYPES = {"png", "jpeg", "gif", "svg+xml", "webp"}
def build_schema(
user_input: dict[str, Any] | MappingProxyType[str, Any],
is_options_flow: bool = False,
show_advanced_options=False,
):
"""Create schema for camera config setup."""
spec = {
@ -106,6 +108,13 @@ def build_schema(
default=user_input.get(CONF_LIMIT_REFETCH_TO_URL_CHANGE, False),
)
] = bool
if show_advanced_options:
spec[
vol.Required(
CONF_USE_WALLCLOCK_AS_TIMESTAMPS,
default=user_input.get(CONF_USE_WALLCLOCK_AS_TIMESTAMPS, False),
)
] = bool
return vol.Schema(spec)
@ -199,6 +208,8 @@ async def async_test_stream(hass, info) -> dict[str, str]:
}
if rtsp_transport := info.get(CONF_RTSP_TRANSPORT):
stream_options[FFMPEG_OPTION_MAP[CONF_RTSP_TRANSPORT]] = rtsp_transport
if info.get(CONF_USE_WALLCLOCK_AS_TIMESTAMPS):
stream_options[FFMPEG_OPTION_MAP[CONF_USE_WALLCLOCK_AS_TIMESTAMPS]] = "1"
_LOGGER.debug("Attempting to open stream %s", stream_source)
container = await hass.async_add_executor_job(
partial(
@ -356,6 +367,9 @@ class GenericOptionsFlowHandler(OptionsFlow):
],
CONF_FRAMERATE: user_input[CONF_FRAMERATE],
CONF_VERIFY_SSL: user_input[CONF_VERIFY_SSL],
CONF_USE_WALLCLOCK_AS_TIMESTAMPS: user_input.get(
CONF_USE_WALLCLOCK_AS_TIMESTAMPS
),
}
return self.async_create_entry(
title=title,
@ -363,6 +377,10 @@ class GenericOptionsFlowHandler(OptionsFlow):
)
return self.async_show_form(
step_id="init",
data_schema=build_schema(user_input or self.config_entry.options, True),
data_schema=build_schema(
user_input or self.config_entry.options,
True,
self.show_advanced_options,
),
errors=errors,
)

View File

@ -8,7 +8,11 @@ CONF_STILL_IMAGE_URL = "still_image_url"
CONF_STREAM_SOURCE = "stream_source"
CONF_FRAMERATE = "framerate"
CONF_RTSP_TRANSPORT = "rtsp_transport"
FFMPEG_OPTION_MAP = {CONF_RTSP_TRANSPORT: "rtsp_transport"}
CONF_USE_WALLCLOCK_AS_TIMESTAMPS = "use_wallclock_as_timestamps"
FFMPEG_OPTION_MAP = {
CONF_RTSP_TRANSPORT: "rtsp_transport",
CONF_USE_WALLCLOCK_AS_TIMESTAMPS: "use_wallclock_as_timestamps",
}
RTSP_TRANSPORTS = {
"tcp": "TCP",
"udp": "UDP",

View File

@ -55,9 +55,13 @@
"authentication": "[%key:component::generic::config::step::user::data::authentication%]",
"limit_refetch_to_url_change": "[%key:component::generic::config::step::user::data::limit_refetch_to_url_change%]",
"password": "[%key:common::config_flow::data::password%]",
"use_wallclock_as_timestamps": "Use wallclock as timestamps",
"username": "[%key:common::config_flow::data::username%]",
"framerate": "[%key:component::generic::config::step::user::data::framerate%]",
"verify_ssl": "[%key:common::config_flow::data::verify_ssl%]"
},
"data_description": {
"use_wallclock_as_timestamps": "This option may correct segmenting or crashing issues arising from buggy timestamp implementations on some cameras"
}
},
"content_type": {

View File

@ -32,7 +32,6 @@
"user": {
"data": {
"authentication": "Authentication",
"content_type": "Content Type",
"framerate": "Frame Rate (Hz)",
"limit_refetch_to_url_change": "Limit refetch to url change",
"password": "Password",
@ -72,15 +71,18 @@
"init": {
"data": {
"authentication": "Authentication",
"content_type": "Content Type",
"framerate": "Frame Rate (Hz)",
"limit_refetch_to_url_change": "Limit refetch to url change",
"password": "Password",
"rtsp_transport": "RTSP transport protocol",
"still_image_url": "Still Image URL (e.g. http://...)",
"stream_source": "Stream Source URL (e.g. rtsp://...)",
"use_wallclock_as_timestamps": "Use wallclock as timestamps",
"username": "Username",
"verify_ssl": "Verify SSL certificate"
},
"data_description": {
"use_wallclock_as_timestamps": "This option may correct segmenting or crashing issues arising from buggy timestamp implementations on some cameras"
}
}
}

View File

@ -18,6 +18,7 @@ from homeassistant.components.generic.const import (
CONF_RTSP_TRANSPORT,
CONF_STILL_IMAGE_URL,
CONF_STREAM_SOURCE,
CONF_USE_WALLCLOCK_AS_TIMESTAMPS,
DOMAIN,
)
from homeassistant.const import (
@ -653,3 +654,32 @@ async def test_migrate_existing_ids(hass) -> None:
entity_entry = registry.async_get(entity_id)
assert entity_entry.unique_id == new_unique_id
@respx.mock
async def test_use_wallclock_as_timestamps_option(hass, fakeimg_png, mock_av_open):
"""Test the use_wallclock_as_timestamps option flow."""
mock_entry = MockConfigEntry(
title="Test Camera",
domain=DOMAIN,
data={},
options=TESTDATA,
)
with mock_av_open:
mock_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_entry.entry_id)
await hass.async_block_till_done()
result = await hass.config_entries.options.async_init(
mock_entry.entry_id, context={"show_advanced_options": True}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "init"
result2 = await hass.config_entries.options.async_configure(
result["flow_id"],
user_input={CONF_USE_WALLCLOCK_AS_TIMESTAMPS: True, **TESTDATA},
)
assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY