add option to set content_type in camera.generic to support 'svg cameras' (#8188)
* add custom content_type to support 'generic svg cameras' * add unittest to check content_type for svg generic camera * Tweak tests
This commit is contained in:
parent
7bf6ceafec
commit
4ca5ed25bc
3 changed files with 52 additions and 7 deletions
|
@ -38,6 +38,7 @@ STATE_RECORDING = 'recording'
|
|||
STATE_STREAMING = 'streaming'
|
||||
STATE_IDLE = 'idle'
|
||||
|
||||
DEFAULT_CONTENT_TYPE = 'image/jpeg'
|
||||
ENTITY_IMAGE_URL = '/api/camera_proxy/{0}?token={1}'
|
||||
|
||||
TOKEN_CHANGE_INTERVAL = timedelta(minutes=5)
|
||||
|
@ -101,6 +102,7 @@ class Camera(Entity):
|
|||
def __init__(self):
|
||||
"""Initialize a camera."""
|
||||
self.is_streaming = False
|
||||
self.content_type = DEFAULT_CONTENT_TYPE
|
||||
self.access_tokens = collections.deque([], 2)
|
||||
self.async_update_token()
|
||||
|
||||
|
@ -149,16 +151,17 @@ class Camera(Entity):
|
|||
response = web.StreamResponse()
|
||||
|
||||
response.content_type = ('multipart/x-mixed-replace; '
|
||||
'boundary=--jpegboundary')
|
||||
'boundary=--frameboundary')
|
||||
yield from response.prepare(request)
|
||||
|
||||
def write(img_bytes):
|
||||
"""Write image to stream."""
|
||||
response.write(bytes(
|
||||
'--jpegboundary\r\n'
|
||||
'Content-Type: image/jpeg\r\n'
|
||||
'--frameboundary\r\n'
|
||||
'Content-Type: {}\r\n'
|
||||
'Content-Length: {}\r\n\r\n'.format(
|
||||
len(img_bytes)), 'utf-8') + img_bytes + b'\r\n')
|
||||
self.content_type, len(img_bytes)),
|
||||
'utf-8') + img_bytes + b'\r\n')
|
||||
|
||||
last_image = None
|
||||
|
||||
|
@ -269,7 +272,8 @@ class CameraImageView(CameraView):
|
|||
image = yield from camera.async_camera_image()
|
||||
|
||||
if image:
|
||||
return web.Response(body=image, content_type='image/jpeg')
|
||||
return web.Response(body=image,
|
||||
content_type=camera.content_type)
|
||||
|
||||
return web.Response(status=500)
|
||||
|
||||
|
|
|
@ -17,13 +17,15 @@ from homeassistant.const import (
|
|||
CONF_NAME, CONF_USERNAME, CONF_PASSWORD, CONF_AUTHENTICATION,
|
||||
HTTP_BASIC_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION)
|
||||
from homeassistant.exceptions import TemplateError
|
||||
from homeassistant.components.camera import (PLATFORM_SCHEMA, Camera)
|
||||
from homeassistant.components.camera import (
|
||||
PLATFORM_SCHEMA, DEFAULT_CONTENT_TYPE, Camera)
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.util.async import run_coroutine_threadsafe
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_CONTENT_TYPE = 'content_type'
|
||||
CONF_LIMIT_REFETCH_TO_URL_CHANGE = 'limit_refetch_to_url_change'
|
||||
CONF_STILL_IMAGE_URL = 'still_image_url'
|
||||
|
||||
|
@ -37,6 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
|||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
vol.Optional(CONF_PASSWORD): cv.string,
|
||||
vol.Optional(CONF_USERNAME): cv.string,
|
||||
vol.Optional(CONF_CONTENT_TYPE, default=DEFAULT_CONTENT_TYPE): cv.string,
|
||||
})
|
||||
|
||||
|
||||
|
@ -59,6 +62,7 @@ class GenericCamera(Camera):
|
|||
self._still_image_url = device_info[CONF_STILL_IMAGE_URL]
|
||||
self._still_image_url.hass = hass
|
||||
self._limit_refetch = device_info[CONF_LIMIT_REFETCH_TO_URL_CHANGE]
|
||||
self.content_type = device_info[CONF_CONTENT_TYPE]
|
||||
|
||||
username = device_info.get(CONF_USERNAME)
|
||||
password = device_info.get(CONF_PASSWORD)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import asyncio
|
||||
from unittest import mock
|
||||
|
||||
from homeassistant.setup import setup_component
|
||||
from homeassistant.setup import setup_component, async_setup_component
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
|
@ -99,3 +99,40 @@ def test_limit_refetch(aioclient_mock, hass, test_client):
|
|||
assert resp.status == 200
|
||||
body = yield from resp.text()
|
||||
assert body == 'hello planet'
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_camera_content_type(aioclient_mock, hass, test_client):
|
||||
"""Test generic camera with custom content_type."""
|
||||
svg_image = '<some image>'
|
||||
urlsvg = 'https://upload.wikimedia.org/wikipedia/commons/0/02/SVG_logo.svg'
|
||||
aioclient_mock.get(urlsvg, text=svg_image)
|
||||
|
||||
cam_config_svg = {
|
||||
'name': 'config_test_svg',
|
||||
'platform': 'generic',
|
||||
'still_image_url': urlsvg,
|
||||
'content_type': 'image/svg+xml',
|
||||
}
|
||||
cam_config_normal = cam_config_svg.copy()
|
||||
cam_config_normal.pop('content_type')
|
||||
cam_config_normal['name'] = 'config_test_jpg'
|
||||
|
||||
yield from async_setup_component(hass, 'camera', {
|
||||
'camera': [cam_config_svg, cam_config_normal]})
|
||||
|
||||
client = yield from test_client(hass.http.app)
|
||||
|
||||
resp_1 = yield from client.get('/api/camera_proxy/camera.config_test_svg')
|
||||
assert aioclient_mock.call_count == 1
|
||||
assert resp_1.status == 200
|
||||
assert resp_1.content_type == 'image/svg+xml'
|
||||
body = yield from resp_1.text()
|
||||
assert body == svg_image
|
||||
|
||||
resp_2 = yield from client.get('/api/camera_proxy/camera.config_test_jpg')
|
||||
assert aioclient_mock.call_count == 2
|
||||
assert resp_2.status == 200
|
||||
assert resp_2.content_type == 'image/jpeg'
|
||||
body = yield from resp_2.text()
|
||||
assert body == svg_image
|
||||
|
|
Loading…
Add table
Reference in a new issue