mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 07:07:28 +00:00
Remove deprecated camera frontend_stream_type (#144539)
This commit is contained in:
parent
6350ed3415
commit
c4ceb4759a
@ -61,7 +61,6 @@ from homeassistant.helpers.deprecation import (
|
|||||||
from homeassistant.helpers.entity import Entity, EntityDescription
|
from homeassistant.helpers.entity import Entity, EntityDescription
|
||||||
from homeassistant.helpers.entity_component import EntityComponent
|
from homeassistant.helpers.entity_component import EntityComponent
|
||||||
from homeassistant.helpers.event import async_track_time_interval
|
from homeassistant.helpers.event import async_track_time_interval
|
||||||
from homeassistant.helpers.frame import ReportBehavior, report_usage
|
|
||||||
from homeassistant.helpers.network import get_url
|
from homeassistant.helpers.network import get_url
|
||||||
from homeassistant.helpers.template import Template
|
from homeassistant.helpers.template import Template
|
||||||
from homeassistant.helpers.typing import ConfigType, VolDictType
|
from homeassistant.helpers.typing import ConfigType, VolDictType
|
||||||
@ -436,7 +435,6 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
CACHED_PROPERTIES_WITH_ATTR_ = {
|
CACHED_PROPERTIES_WITH_ATTR_ = {
|
||||||
"brand",
|
"brand",
|
||||||
"frame_interval",
|
"frame_interval",
|
||||||
"frontend_stream_type",
|
|
||||||
"is_on",
|
"is_on",
|
||||||
"is_recording",
|
"is_recording",
|
||||||
"is_streaming",
|
"is_streaming",
|
||||||
@ -456,8 +454,6 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||||||
# Entity Properties
|
# Entity Properties
|
||||||
_attr_brand: str | None = None
|
_attr_brand: str | None = None
|
||||||
_attr_frame_interval: float = MIN_STREAM_INTERVAL
|
_attr_frame_interval: float = MIN_STREAM_INTERVAL
|
||||||
# Deprecated in 2024.12. Remove in 2025.6
|
|
||||||
_attr_frontend_stream_type: StreamType | None
|
|
||||||
_attr_is_on: bool = True
|
_attr_is_on: bool = True
|
||||||
_attr_is_recording: bool = False
|
_attr_is_recording: bool = False
|
||||||
_attr_is_streaming: bool = False
|
_attr_is_streaming: bool = False
|
||||||
@ -488,16 +484,6 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||||||
type(self).async_handle_async_webrtc_offer
|
type(self).async_handle_async_webrtc_offer
|
||||||
!= Camera.async_handle_async_webrtc_offer
|
!= Camera.async_handle_async_webrtc_offer
|
||||||
)
|
)
|
||||||
self._deprecate_attr_frontend_stream_type_logged = False
|
|
||||||
if type(self).frontend_stream_type != Camera.frontend_stream_type:
|
|
||||||
report_usage(
|
|
||||||
(
|
|
||||||
f"is overwriting the 'frontend_stream_type' property in the {type(self).__name__} class,"
|
|
||||||
" which is deprecated and will be removed in Home Assistant 2025.6, "
|
|
||||||
),
|
|
||||||
core_integration_behavior=ReportBehavior.ERROR,
|
|
||||||
exclude_integrations={DOMAIN},
|
|
||||||
)
|
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def entity_picture(self) -> str:
|
def entity_picture(self) -> str:
|
||||||
@ -559,40 +545,6 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||||||
"""Return the interval between frames of the mjpeg stream."""
|
"""Return the interval between frames of the mjpeg stream."""
|
||||||
return self._attr_frame_interval
|
return self._attr_frame_interval
|
||||||
|
|
||||||
@property
|
|
||||||
def frontend_stream_type(self) -> StreamType | None:
|
|
||||||
"""Return the type of stream supported by this camera.
|
|
||||||
|
|
||||||
A camera may have a single stream type which is used to inform the
|
|
||||||
frontend which camera attributes and player to use. The default type
|
|
||||||
is to use HLS, and components can override to change the type.
|
|
||||||
"""
|
|
||||||
# Deprecated in 2024.12. Remove in 2025.6
|
|
||||||
# Use the camera_capabilities instead
|
|
||||||
if hasattr(self, "_attr_frontend_stream_type"):
|
|
||||||
if not self._deprecate_attr_frontend_stream_type_logged:
|
|
||||||
report_usage(
|
|
||||||
(
|
|
||||||
f"is setting the '_attr_frontend_stream_type' attribute in the {type(self).__name__} class,"
|
|
||||||
" which is deprecated and will be removed in Home Assistant 2025.6, "
|
|
||||||
),
|
|
||||||
core_integration_behavior=ReportBehavior.ERROR,
|
|
||||||
exclude_integrations={DOMAIN},
|
|
||||||
)
|
|
||||||
|
|
||||||
self._deprecate_attr_frontend_stream_type_logged = True
|
|
||||||
return self._attr_frontend_stream_type
|
|
||||||
if CameraEntityFeature.STREAM not in self.supported_features_compat:
|
|
||||||
return None
|
|
||||||
if (
|
|
||||||
self._webrtc_provider
|
|
||||||
or self._legacy_webrtc_provider
|
|
||||||
or self._supports_native_sync_webrtc
|
|
||||||
or self._supports_native_async_webrtc
|
|
||||||
):
|
|
||||||
return StreamType.WEB_RTC
|
|
||||||
return StreamType.HLS
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available(self) -> bool:
|
def available(self) -> bool:
|
||||||
"""Return True if entity is available."""
|
"""Return True if entity is available."""
|
||||||
@ -797,9 +749,6 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||||||
if motion_detection_enabled := self.motion_detection_enabled:
|
if motion_detection_enabled := self.motion_detection_enabled:
|
||||||
attrs["motion_detection"] = motion_detection_enabled
|
attrs["motion_detection"] = motion_detection_enabled
|
||||||
|
|
||||||
if frontend_stream_type := self.frontend_stream_type:
|
|
||||||
attrs["frontend_stream_type"] = frontend_stream_type
|
|
||||||
|
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
@ -39,7 +39,6 @@
|
|||||||
'access_token': '1',
|
'access_token': '1',
|
||||||
'entity_picture': '/api/camera_proxy/camera.home?token=1',
|
'entity_picture': '/api/camera_proxy/camera.home?token=1',
|
||||||
'friendly_name': 'home',
|
'friendly_name': 'home',
|
||||||
'frontend_stream_type': <StreamType.HLS: 'hls'>,
|
|
||||||
'supported_features': <CameraEntityFeature: 2>,
|
'supported_features': <CameraEntityFeature: 2>,
|
||||||
}),
|
}),
|
||||||
'context': <ANY>,
|
'context': <ANY>,
|
||||||
@ -90,7 +89,6 @@
|
|||||||
'access_token': '1',
|
'access_token': '1',
|
||||||
'entity_picture': '/api/camera_proxy/camera.home?token=1',
|
'entity_picture': '/api/camera_proxy/camera.home?token=1',
|
||||||
'friendly_name': 'home',
|
'friendly_name': 'home',
|
||||||
'frontend_stream_type': <StreamType.HLS: 'hls'>,
|
|
||||||
'supported_features': <CameraEntityFeature: 2>,
|
'supported_features': <CameraEntityFeature: 2>,
|
||||||
}),
|
}),
|
||||||
'context': <ANY>,
|
'context': <ANY>,
|
||||||
|
@ -27,7 +27,6 @@ from homeassistant.components.camera.helper import get_camera_from_entity_id
|
|||||||
from homeassistant.components.websocket_api import TYPE_RESULT
|
from homeassistant.components.websocket_api import TYPE_RESULT
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
CONF_PLATFORM,
|
|
||||||
EVENT_HOMEASSISTANT_STARTED,
|
EVENT_HOMEASSISTANT_STARTED,
|
||||||
STATE_UNAVAILABLE,
|
STATE_UNAVAILABLE,
|
||||||
)
|
)
|
||||||
@ -1036,27 +1035,3 @@ async def test_camera_capabilities_changing_native_support(
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
await _test_capabilities(hass, hass_ws_client, cam.entity_id, set(), set())
|
await _test_capabilities(hass, hass_ws_client, cam.entity_id, set(), set())
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("enable_custom_integrations")
|
|
||||||
async def test_deprecated_frontend_stream_type_logs(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
caplog: pytest.LogCaptureFixture,
|
|
||||||
) -> None:
|
|
||||||
"""Test using (_attr_)frontend_stream_type will log."""
|
|
||||||
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}})
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
for entity_id in (
|
|
||||||
"camera.property_frontend_stream_type",
|
|
||||||
"camera.attr_frontend_stream_type",
|
|
||||||
):
|
|
||||||
camera_obj = get_camera_from_entity_id(hass, entity_id)
|
|
||||||
assert camera_obj.frontend_stream_type == StreamType.WEB_RTC
|
|
||||||
|
|
||||||
assert (
|
|
||||||
"Detected that custom integration 'test' is overwriting the 'frontend_stream_type' property in the PropertyFrontendStreamTypeCamera class, which is deprecated and will be removed in Home Assistant 2025.6,"
|
|
||||||
) in caplog.text
|
|
||||||
assert (
|
|
||||||
"Detected that custom integration 'test' is setting the '_attr_frontend_stream_type' attribute in the AttrFrontendStreamTypeCamera class, which is deprecated and will be removed in Home Assistant 2025.6,"
|
|
||||||
) in caplog.text
|
|
||||||
|
@ -826,7 +826,6 @@ async def test_camera_multiple_streams(
|
|||||||
assert cam is not None
|
assert cam is not None
|
||||||
assert cam.state == CameraState.STREAMING
|
assert cam.state == CameraState.STREAMING
|
||||||
# Prefer WebRTC over RTSP/HLS
|
# Prefer WebRTC over RTSP/HLS
|
||||||
assert cam.attributes["frontend_stream_type"] == StreamType.WEB_RTC
|
|
||||||
client = await hass_ws_client(hass)
|
client = await hass_ws_client(hass)
|
||||||
assert await async_frontend_stream_types(client, "camera.my_camera") == [
|
assert await async_frontend_stream_types(client, "camera.my_camera") == [
|
||||||
StreamType.WEB_RTC
|
StreamType.WEB_RTC
|
||||||
@ -905,7 +904,6 @@ async def test_webrtc_refresh_expired_stream(
|
|||||||
cam = hass.states.get("camera.my_camera")
|
cam = hass.states.get("camera.my_camera")
|
||||||
assert cam is not None
|
assert cam is not None
|
||||||
assert cam.state == CameraState.STREAMING
|
assert cam.state == CameraState.STREAMING
|
||||||
assert cam.attributes["frontend_stream_type"] == StreamType.WEB_RTC
|
|
||||||
client = await hass_ws_client(hass)
|
client = await hass_ws_client(hass)
|
||||||
assert await async_frontend_stream_types(client, "camera.my_camera") == [
|
assert await async_frontend_stream_types(client, "camera.my_camera") == [
|
||||||
StreamType.WEB_RTC
|
StreamType.WEB_RTC
|
||||||
|
@ -42,7 +42,6 @@
|
|||||||
'brand': 'Netatmo',
|
'brand': 'Netatmo',
|
||||||
'entity_picture': '/api/camera_proxy/camera.front?token=1caab5c3b3',
|
'entity_picture': '/api/camera_proxy/camera.front?token=1caab5c3b3',
|
||||||
'friendly_name': 'Front',
|
'friendly_name': 'Front',
|
||||||
'frontend_stream_type': <StreamType.HLS: 'hls'>,
|
|
||||||
'id': '12:34:56:10:b9:0e',
|
'id': '12:34:56:10:b9:0e',
|
||||||
'is_local': False,
|
'is_local': False,
|
||||||
'light_state': None,
|
'light_state': None,
|
||||||
@ -104,7 +103,6 @@
|
|||||||
'brand': 'Netatmo',
|
'brand': 'Netatmo',
|
||||||
'entity_picture': '/api/camera_proxy/camera.hall?token=1caab5c3b3',
|
'entity_picture': '/api/camera_proxy/camera.hall?token=1caab5c3b3',
|
||||||
'friendly_name': 'Hall',
|
'friendly_name': 'Hall',
|
||||||
'frontend_stream_type': <StreamType.HLS: 'hls'>,
|
|
||||||
'id': '12:34:56:00:f1:62',
|
'id': '12:34:56:00:f1:62',
|
||||||
'is_local': True,
|
'is_local': True,
|
||||||
'light_state': None,
|
'light_state': None,
|
||||||
|
@ -94,7 +94,6 @@
|
|||||||
'attribution': 'Data provided by Ring.com',
|
'attribution': 'Data provided by Ring.com',
|
||||||
'entity_picture': '/api/camera_proxy/camera.front_door_live_view?token=1caab5c3b3',
|
'entity_picture': '/api/camera_proxy/camera.front_door_live_view?token=1caab5c3b3',
|
||||||
'friendly_name': 'Front Door Live view',
|
'friendly_name': 'Front Door Live view',
|
||||||
'frontend_stream_type': <StreamType.WEB_RTC: 'web_rtc'>,
|
|
||||||
'last_video_id': None,
|
'last_video_id': None,
|
||||||
'supported_features': <CameraEntityFeature: 2>,
|
'supported_features': <CameraEntityFeature: 2>,
|
||||||
'video_url': None,
|
'video_url': None,
|
||||||
@ -201,7 +200,6 @@
|
|||||||
'attribution': 'Data provided by Ring.com',
|
'attribution': 'Data provided by Ring.com',
|
||||||
'entity_picture': '/api/camera_proxy/camera.front_live_view?token=1caab5c3b3',
|
'entity_picture': '/api/camera_proxy/camera.front_live_view?token=1caab5c3b3',
|
||||||
'friendly_name': 'Front Live view',
|
'friendly_name': 'Front Live view',
|
||||||
'frontend_stream_type': <StreamType.WEB_RTC: 'web_rtc'>,
|
|
||||||
'last_video_id': None,
|
'last_video_id': None,
|
||||||
'supported_features': <CameraEntityFeature: 2>,
|
'supported_features': <CameraEntityFeature: 2>,
|
||||||
'video_url': None,
|
'video_url': None,
|
||||||
@ -309,7 +307,6 @@
|
|||||||
'attribution': 'Data provided by Ring.com',
|
'attribution': 'Data provided by Ring.com',
|
||||||
'entity_picture': '/api/camera_proxy/camera.internal_live_view?token=1caab5c3b3',
|
'entity_picture': '/api/camera_proxy/camera.internal_live_view?token=1caab5c3b3',
|
||||||
'friendly_name': 'Internal Live view',
|
'friendly_name': 'Internal Live view',
|
||||||
'frontend_stream_type': <StreamType.WEB_RTC: 'web_rtc'>,
|
|
||||||
'last_video_id': None,
|
'last_video_id': None,
|
||||||
'supported_features': <CameraEntityFeature: 2>,
|
'supported_features': <CameraEntityFeature: 2>,
|
||||||
'video_url': None,
|
'video_url': None,
|
||||||
|
@ -39,7 +39,6 @@
|
|||||||
'access_token': '1caab5c3b3',
|
'access_token': '1caab5c3b3',
|
||||||
'entity_picture': '/api/camera_proxy/camera.my_camera_live_view?token=1caab5c3b3',
|
'entity_picture': '/api/camera_proxy/camera.my_camera_live_view?token=1caab5c3b3',
|
||||||
'friendly_name': 'my_camera Live view',
|
'friendly_name': 'my_camera Live view',
|
||||||
'frontend_stream_type': <StreamType.HLS: 'hls'>,
|
|
||||||
'supported_features': <CameraEntityFeature: 3>,
|
'supported_features': <CameraEntityFeature: 3>,
|
||||||
}),
|
}),
|
||||||
'context': <ANY>,
|
'context': <ANY>,
|
||||||
|
@ -12,6 +12,7 @@ from uiprotect.websocket import WebsocketState
|
|||||||
from webrtc_models import RTCIceCandidateInit
|
from webrtc_models import RTCIceCandidateInit
|
||||||
|
|
||||||
from homeassistant.components.camera import (
|
from homeassistant.components.camera import (
|
||||||
|
CameraCapabilities,
|
||||||
CameraEntityFeature,
|
CameraEntityFeature,
|
||||||
CameraState,
|
CameraState,
|
||||||
CameraWebRTCProvider,
|
CameraWebRTCProvider,
|
||||||
@ -21,6 +22,7 @@ from homeassistant.components.camera import (
|
|||||||
async_get_stream_source,
|
async_get_stream_source,
|
||||||
async_register_webrtc_provider,
|
async_register_webrtc_provider,
|
||||||
)
|
)
|
||||||
|
from homeassistant.components.camera.helper import get_camera_from_entity_id
|
||||||
from homeassistant.components.unifiprotect.const import (
|
from homeassistant.components.unifiprotect.const import (
|
||||||
ATTR_BITRATE,
|
ATTR_BITRATE,
|
||||||
ATTR_CHANNEL_ID,
|
ATTR_CHANNEL_ID,
|
||||||
@ -345,9 +347,11 @@ async def test_webrtc_support(
|
|||||||
camera_high_only.channels[2].is_rtsp_enabled = False
|
camera_high_only.channels[2].is_rtsp_enabled = False
|
||||||
await init_entry(hass, ufp, [camera_high_only])
|
await init_entry(hass, ufp, [camera_high_only])
|
||||||
entity_id = validate_default_camera_entity(hass, camera_high_only, 0)
|
entity_id = validate_default_camera_entity(hass, camera_high_only, 0)
|
||||||
state = hass.states.get(entity_id)
|
assert hass.states.get(entity_id)
|
||||||
assert state
|
camera_obj = get_camera_from_entity_id(hass, entity_id)
|
||||||
assert StreamType.WEB_RTC in state.attributes["frontend_stream_type"]
|
assert camera_obj.camera_capabilities == CameraCapabilities(
|
||||||
|
{StreamType.HLS, StreamType.WEB_RTC}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_adopt(
|
async def test_adopt(
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
"""Provide a mock remote platform.
|
|
||||||
|
|
||||||
Call init before using it in your tests to ensure clean test data.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from homeassistant.components.camera import Camera, CameraEntityFeature, StreamType
|
|
||||||
from homeassistant.core import HomeAssistant
|
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
config: ConfigType,
|
|
||||||
async_add_entities_callback: AddEntitiesCallback,
|
|
||||||
discovery_info: DiscoveryInfoType | None = None,
|
|
||||||
) -> None:
|
|
||||||
"""Return mock entities."""
|
|
||||||
async_add_entities_callback(
|
|
||||||
[AttrFrontendStreamTypeCamera(), PropertyFrontendStreamTypeCamera()]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class AttrFrontendStreamTypeCamera(Camera):
|
|
||||||
"""attr frontend stream type Camera."""
|
|
||||||
|
|
||||||
_attr_name = "attr frontend stream type"
|
|
||||||
_attr_supported_features: CameraEntityFeature = CameraEntityFeature.STREAM
|
|
||||||
_attr_frontend_stream_type: StreamType = StreamType.WEB_RTC
|
|
||||||
|
|
||||||
|
|
||||||
class PropertyFrontendStreamTypeCamera(Camera):
|
|
||||||
"""property frontend stream type Camera."""
|
|
||||||
|
|
||||||
_attr_name = "property frontend stream type"
|
|
||||||
_attr_supported_features: CameraEntityFeature = CameraEntityFeature.STREAM
|
|
||||||
|
|
||||||
@property
|
|
||||||
def frontend_stream_type(self) -> StreamType | None:
|
|
||||||
"""Return the stream type of the camera."""
|
|
||||||
return StreamType.WEB_RTC
|
|
Loading…
x
Reference in New Issue
Block a user