mirror of
https://github.com/home-assistant/core.git
synced 2025-07-14 08:47:10 +00:00
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:
parent
a746d7c1d7
commit
7e49ae6410
@ -37,6 +37,7 @@ from .const import (
|
|||||||
CONF_RTSP_TRANSPORT,
|
CONF_RTSP_TRANSPORT,
|
||||||
CONF_STILL_IMAGE_URL,
|
CONF_STILL_IMAGE_URL,
|
||||||
CONF_STREAM_SOURCE,
|
CONF_STREAM_SOURCE,
|
||||||
|
CONF_USE_WALLCLOCK_AS_TIMESTAMPS,
|
||||||
DEFAULT_NAME,
|
DEFAULT_NAME,
|
||||||
FFMPEG_OPTION_MAP,
|
FFMPEG_OPTION_MAP,
|
||||||
GET_IMAGE_TIMEOUT,
|
GET_IMAGE_TIMEOUT,
|
||||||
@ -160,6 +161,10 @@ class GenericCamera(Camera):
|
|||||||
CONF_RTSP_TRANSPORT
|
CONF_RTSP_TRANSPORT
|
||||||
]
|
]
|
||||||
self._auth = generate_auth(device_info)
|
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_url = None
|
||||||
self._last_image = None
|
self._last_image = None
|
||||||
|
@ -41,6 +41,7 @@ from .const import (
|
|||||||
CONF_RTSP_TRANSPORT,
|
CONF_RTSP_TRANSPORT,
|
||||||
CONF_STILL_IMAGE_URL,
|
CONF_STILL_IMAGE_URL,
|
||||||
CONF_STREAM_SOURCE,
|
CONF_STREAM_SOURCE,
|
||||||
|
CONF_USE_WALLCLOCK_AS_TIMESTAMPS,
|
||||||
DEFAULT_NAME,
|
DEFAULT_NAME,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
FFMPEG_OPTION_MAP,
|
FFMPEG_OPTION_MAP,
|
||||||
@ -64,6 +65,7 @@ SUPPORTED_IMAGE_TYPES = {"png", "jpeg", "gif", "svg+xml", "webp"}
|
|||||||
def build_schema(
|
def build_schema(
|
||||||
user_input: dict[str, Any] | MappingProxyType[str, Any],
|
user_input: dict[str, Any] | MappingProxyType[str, Any],
|
||||||
is_options_flow: bool = False,
|
is_options_flow: bool = False,
|
||||||
|
show_advanced_options=False,
|
||||||
):
|
):
|
||||||
"""Create schema for camera config setup."""
|
"""Create schema for camera config setup."""
|
||||||
spec = {
|
spec = {
|
||||||
@ -106,6 +108,13 @@ def build_schema(
|
|||||||
default=user_input.get(CONF_LIMIT_REFETCH_TO_URL_CHANGE, False),
|
default=user_input.get(CONF_LIMIT_REFETCH_TO_URL_CHANGE, False),
|
||||||
)
|
)
|
||||||
] = bool
|
] = 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)
|
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):
|
if rtsp_transport := info.get(CONF_RTSP_TRANSPORT):
|
||||||
stream_options[FFMPEG_OPTION_MAP[CONF_RTSP_TRANSPORT]] = 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)
|
_LOGGER.debug("Attempting to open stream %s", stream_source)
|
||||||
container = await hass.async_add_executor_job(
|
container = await hass.async_add_executor_job(
|
||||||
partial(
|
partial(
|
||||||
@ -356,6 +367,9 @@ class GenericOptionsFlowHandler(OptionsFlow):
|
|||||||
],
|
],
|
||||||
CONF_FRAMERATE: user_input[CONF_FRAMERATE],
|
CONF_FRAMERATE: user_input[CONF_FRAMERATE],
|
||||||
CONF_VERIFY_SSL: user_input[CONF_VERIFY_SSL],
|
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(
|
return self.async_create_entry(
|
||||||
title=title,
|
title=title,
|
||||||
@ -363,6 +377,10 @@ class GenericOptionsFlowHandler(OptionsFlow):
|
|||||||
)
|
)
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="init",
|
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,
|
errors=errors,
|
||||||
)
|
)
|
||||||
|
@ -8,7 +8,11 @@ CONF_STILL_IMAGE_URL = "still_image_url"
|
|||||||
CONF_STREAM_SOURCE = "stream_source"
|
CONF_STREAM_SOURCE = "stream_source"
|
||||||
CONF_FRAMERATE = "framerate"
|
CONF_FRAMERATE = "framerate"
|
||||||
CONF_RTSP_TRANSPORT = "rtsp_transport"
|
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 = {
|
RTSP_TRANSPORTS = {
|
||||||
"tcp": "TCP",
|
"tcp": "TCP",
|
||||||
"udp": "UDP",
|
"udp": "UDP",
|
||||||
|
@ -55,9 +55,13 @@
|
|||||||
"authentication": "[%key:component::generic::config::step::user::data::authentication%]",
|
"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%]",
|
"limit_refetch_to_url_change": "[%key:component::generic::config::step::user::data::limit_refetch_to_url_change%]",
|
||||||
"password": "[%key:common::config_flow::data::password%]",
|
"password": "[%key:common::config_flow::data::password%]",
|
||||||
|
"use_wallclock_as_timestamps": "Use wallclock as timestamps",
|
||||||
"username": "[%key:common::config_flow::data::username%]",
|
"username": "[%key:common::config_flow::data::username%]",
|
||||||
"framerate": "[%key:component::generic::config::step::user::data::framerate%]",
|
"framerate": "[%key:component::generic::config::step::user::data::framerate%]",
|
||||||
"verify_ssl": "[%key:common::config_flow::data::verify_ssl%]"
|
"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": {
|
"content_type": {
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
"user": {
|
"user": {
|
||||||
"data": {
|
"data": {
|
||||||
"authentication": "Authentication",
|
"authentication": "Authentication",
|
||||||
"content_type": "Content Type",
|
|
||||||
"framerate": "Frame Rate (Hz)",
|
"framerate": "Frame Rate (Hz)",
|
||||||
"limit_refetch_to_url_change": "Limit refetch to url change",
|
"limit_refetch_to_url_change": "Limit refetch to url change",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
@ -72,15 +71,18 @@
|
|||||||
"init": {
|
"init": {
|
||||||
"data": {
|
"data": {
|
||||||
"authentication": "Authentication",
|
"authentication": "Authentication",
|
||||||
"content_type": "Content Type",
|
|
||||||
"framerate": "Frame Rate (Hz)",
|
"framerate": "Frame Rate (Hz)",
|
||||||
"limit_refetch_to_url_change": "Limit refetch to url change",
|
"limit_refetch_to_url_change": "Limit refetch to url change",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"rtsp_transport": "RTSP transport protocol",
|
"rtsp_transport": "RTSP transport protocol",
|
||||||
"still_image_url": "Still Image URL (e.g. http://...)",
|
"still_image_url": "Still Image URL (e.g. http://...)",
|
||||||
"stream_source": "Stream Source URL (e.g. rtsp://...)",
|
"stream_source": "Stream Source URL (e.g. rtsp://...)",
|
||||||
|
"use_wallclock_as_timestamps": "Use wallclock as timestamps",
|
||||||
"username": "Username",
|
"username": "Username",
|
||||||
"verify_ssl": "Verify SSL certificate"
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ from homeassistant.components.generic.const import (
|
|||||||
CONF_RTSP_TRANSPORT,
|
CONF_RTSP_TRANSPORT,
|
||||||
CONF_STILL_IMAGE_URL,
|
CONF_STILL_IMAGE_URL,
|
||||||
CONF_STREAM_SOURCE,
|
CONF_STREAM_SOURCE,
|
||||||
|
CONF_USE_WALLCLOCK_AS_TIMESTAMPS,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
@ -653,3 +654,32 @@ async def test_migrate_existing_ids(hass) -> None:
|
|||||||
|
|
||||||
entity_entry = registry.async_get(entity_id)
|
entity_entry = registry.async_get(entity_id)
|
||||||
assert entity_entry.unique_id == new_unique_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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user