Allow camera stream to fail safely (#50728)

This commit is contained in:
Dermot Duffy 2021-05-17 20:34:25 -07:00 committed by GitHub
parent 1f80defe3a
commit 2e1037005c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 4 deletions

View file

@ -160,7 +160,7 @@ async def async_get_stream_source(hass: HomeAssistant, entity_id: str) -> str |
@bind_hass @bind_hass
async def async_get_mjpeg_stream( async def async_get_mjpeg_stream(
hass: HomeAssistant, request: web.Request, entity_id: str hass: HomeAssistant, request: web.Request, entity_id: str
) -> web.StreamResponse: ) -> web.StreamResponse | None:
"""Fetch an mjpeg stream from a camera entity.""" """Fetch an mjpeg stream from a camera entity."""
camera = _get_camera_from_entity_id(hass, entity_id) camera = _get_camera_from_entity_id(hass, entity_id)
@ -399,7 +399,7 @@ class Camera(Entity):
async def handle_async_mjpeg_stream( async def handle_async_mjpeg_stream(
self, request: web.Request self, request: web.Request
) -> web.StreamResponse: ) -> web.StreamResponse | None:
"""Serve an HTTP MJPEG stream from the camera. """Serve an HTTP MJPEG stream from the camera.
This method can be overridden by camera platforms to proxy This method can be overridden by camera platforms to proxy
@ -543,7 +543,10 @@ class CameraMjpegStream(CameraView):
"""Serve camera stream, possibly with interval.""" """Serve camera stream, possibly with interval."""
interval_str = request.query.get("interval") interval_str = request.query.get("interval")
if interval_str is None: if interval_str is None:
return await camera.handle_async_mjpeg_stream(request) stream = await camera.handle_async_mjpeg_stream(request)
if stream is None:
raise web.HTTPBadGateway()
return stream
try: try:
# Compose camera stream from stills # Compose camera stream from stills

View file

@ -11,7 +11,12 @@ from homeassistant.components.camera.const import DOMAIN, PREF_PRELOAD_STREAM
from homeassistant.components.camera.prefs import CameraEntityPreferences from homeassistant.components.camera.prefs import CameraEntityPreferences
from homeassistant.components.websocket_api.const import TYPE_RESULT from homeassistant.components.websocket_api.const import TYPE_RESULT
from homeassistant.config import async_process_ha_core_config from homeassistant.config import async_process_ha_core_config
from homeassistant.const import ATTR_ENTITY_ID, EVENT_HOMEASSISTANT_START from homeassistant.const import (
ATTR_ENTITY_ID,
EVENT_HOMEASSISTANT_START,
HTTP_BAD_GATEWAY,
HTTP_OK,
)
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
@ -354,3 +359,19 @@ async def test_record_service(hass, mock_camera, mock_stream):
# So long as we call stream.record, the rest should be covered # So long as we call stream.record, the rest should be covered
# by those tests. # by those tests.
assert mock_record.called assert mock_record.called
async def test_camera_proxy_stream(hass, mock_camera, hass_client):
"""Test record service."""
client = await hass_client()
response = await client.get("/api/camera_proxy_stream/camera.demo_camera")
assert response.status == HTTP_OK
with patch(
"homeassistant.components.demo.camera.DemoCamera.handle_async_mjpeg_stream",
return_value=None,
):
response = await client.get("/api/camera_proxy_stream/camera.demo_camera")
assert response.status == HTTP_BAD_GATEWAY