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:
Eugenio Panadero 2017-06-25 21:25:14 +02:00 committed by Paulus Schoutsen
parent 7bf6ceafec
commit 4ca5ed25bc
3 changed files with 52 additions and 7 deletions

View file

@ -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)

View file

@ -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)

View file

@ -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