mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
commit
bd3f0c101d
@ -1,8 +1,6 @@
|
|||||||
# pylint: disable=too-many-lines
|
# pylint: disable=too-many-lines
|
||||||
"""
|
"""
|
||||||
homeassistant.components.camera
|
Component to interface with cameras.
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
Component to interface with various cameras.
|
|
||||||
|
|
||||||
For more details about this component, please refer to the documentation at
|
For more details about this component, please refer to the documentation at
|
||||||
https://home-assistant.io/components/camera/
|
https://home-assistant.io/components/camera/
|
||||||
@ -24,33 +22,17 @@ from homeassistant.const import (
|
|||||||
|
|
||||||
DOMAIN = 'camera'
|
DOMAIN = 'camera'
|
||||||
DEPENDENCIES = ['http']
|
DEPENDENCIES = ['http']
|
||||||
GROUP_NAME_ALL_CAMERAS = 'all_cameras'
|
|
||||||
SCAN_INTERVAL = 30
|
SCAN_INTERVAL = 30
|
||||||
ENTITY_ID_FORMAT = DOMAIN + '.{}'
|
ENTITY_ID_FORMAT = DOMAIN + '.{}'
|
||||||
|
|
||||||
SWITCH_ACTION_RECORD = 'record'
|
|
||||||
SWITCH_ACTION_SNAPSHOT = 'snapshot'
|
|
||||||
|
|
||||||
SERVICE_CAMERA = 'camera_service'
|
|
||||||
|
|
||||||
DEFAULT_RECORDING_SECONDS = 30
|
|
||||||
|
|
||||||
# Maps discovered services to their platforms
|
# Maps discovered services to their platforms
|
||||||
DISCOVERY_PLATFORMS = {}
|
DISCOVERY_PLATFORMS = {}
|
||||||
|
|
||||||
FILE_DATETIME_FORMAT = '%Y-%m-%d_%H-%M-%S-%f'
|
|
||||||
DIR_DATETIME_FORMAT = '%Y-%m-%d_%H-%M-%S'
|
|
||||||
|
|
||||||
REC_DIR_PREFIX = 'recording-'
|
|
||||||
REC_IMG_PREFIX = 'recording_image-'
|
|
||||||
|
|
||||||
STATE_RECORDING = 'recording'
|
STATE_RECORDING = 'recording'
|
||||||
STATE_STREAMING = 'streaming'
|
STATE_STREAMING = 'streaming'
|
||||||
STATE_IDLE = 'idle'
|
STATE_IDLE = 'idle'
|
||||||
|
|
||||||
CAMERA_PROXY_URL = '/api/camera_proxy_stream/{0}'
|
ENTITY_IMAGE_URL = '/api/camera_proxy/{0}'
|
||||||
CAMERA_STILL_URL = '/api/camera_proxy/{0}'
|
|
||||||
ENTITY_IMAGE_URL = '/api/camera_proxy/{0}?time={1}'
|
|
||||||
|
|
||||||
MULTIPART_BOUNDARY = '--jpegboundary'
|
MULTIPART_BOUNDARY = '--jpegboundary'
|
||||||
MJPEG_START_HEADER = 'Content-type: {0}\r\n\r\n'
|
MJPEG_START_HEADER = 'Content-type: {0}\r\n\r\n'
|
||||||
@ -58,8 +40,7 @@ MJPEG_START_HEADER = 'Content-type: {0}\r\n\r\n'
|
|||||||
|
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
""" Track states and offer events for cameras. """
|
"""Initialize camera component."""
|
||||||
|
|
||||||
component = EntityComponent(
|
component = EntityComponent(
|
||||||
logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL,
|
logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL,
|
||||||
DISCOVERY_PLATFORMS)
|
DISCOVERY_PLATFORMS)
|
||||||
@ -78,7 +59,7 @@ def setup(hass, config):
|
|||||||
|
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def _proxy_camera_image(handler, path_match, data):
|
def _proxy_camera_image(handler, path_match, data):
|
||||||
""" Proxies the camera image via the HA server. """
|
"""Serve the camera image via the HA server."""
|
||||||
entity_id = path_match.group(ATTR_ENTITY_ID)
|
entity_id = path_match.group(ATTR_ENTITY_ID)
|
||||||
camera = component.entities.get(entity_id)
|
camera = component.entities.get(entity_id)
|
||||||
|
|
||||||
@ -104,7 +85,8 @@ def setup(hass, config):
|
|||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def _proxy_camera_mjpeg_stream(handler, path_match, data):
|
def _proxy_camera_mjpeg_stream(handler, path_match, data):
|
||||||
"""
|
"""
|
||||||
Proxies the camera image as an mjpeg stream via the HA server.
|
Proxy the camera image as an mjpeg stream via the HA server.
|
||||||
|
|
||||||
This function takes still images from the IP camera and turns them
|
This function takes still images from the IP camera and turns them
|
||||||
into an MJPEG stream. This means that HA can return a live video
|
into an MJPEG stream. This means that HA can return a live video
|
||||||
stream even with only a still image URL available.
|
stream even with only a still image URL available.
|
||||||
@ -136,35 +118,41 @@ def setup(hass, config):
|
|||||||
|
|
||||||
|
|
||||||
class Camera(Entity):
|
class Camera(Entity):
|
||||||
""" The base class for camera components. """
|
"""The base class for camera entities."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
"""Initialize a camera."""
|
||||||
self.is_streaming = False
|
self.is_streaming = False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
"""No need to poll cameras."""
|
||||||
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
# pylint: disable=no-self-use
|
# pylint: disable=no-self-use
|
||||||
def is_recording(self):
|
def is_recording(self):
|
||||||
""" Returns true if the device is recording. """
|
"""Return true if the device is recording."""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
# pylint: disable=no-self-use
|
# pylint: disable=no-self-use
|
||||||
def brand(self):
|
def brand(self):
|
||||||
""" Should return a string of the camera brand. """
|
"""Camera brand."""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
# pylint: disable=no-self-use
|
# pylint: disable=no-self-use
|
||||||
def model(self):
|
def model(self):
|
||||||
""" Returns string of camera model. """
|
"""Camera model."""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def camera_image(self):
|
def camera_image(self):
|
||||||
""" Return bytes of camera image. """
|
"""Return bytes of camera image."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def mjpeg_stream(self, handler):
|
def mjpeg_stream(self, handler):
|
||||||
""" Generate an HTTP MJPEG stream from camera images. """
|
"""Generate an HTTP MJPEG stream from camera images."""
|
||||||
handler.request.sendall(bytes('HTTP/1.1 200 OK\r\n', 'utf-8'))
|
handler.request.sendall(bytes('HTTP/1.1 200 OK\r\n', 'utf-8'))
|
||||||
handler.request.sendall(bytes(
|
handler.request.sendall(bytes(
|
||||||
'Content-type: multipart/x-mixed-replace; \
|
'Content-type: multipart/x-mixed-replace; \
|
||||||
@ -193,7 +181,7 @@ class Camera(Entity):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
""" Returns the state of the entity. """
|
"""Camera state."""
|
||||||
if self.is_recording:
|
if self.is_recording:
|
||||||
return STATE_RECORDING
|
return STATE_RECORDING
|
||||||
elif self.is_streaming:
|
elif self.is_streaming:
|
||||||
@ -203,10 +191,9 @@ class Camera(Entity):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def state_attributes(self):
|
def state_attributes(self):
|
||||||
""" Returns optional state attributes. """
|
"""Camera state attributes."""
|
||||||
attr = {
|
attr = {
|
||||||
ATTR_ENTITY_PICTURE: ENTITY_IMAGE_URL.format(
|
ATTR_ENTITY_PICTURE: ENTITY_IMAGE_URL.format(self.entity_id),
|
||||||
self.entity_id, time.time()),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.model:
|
if self.model:
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
""" DO NOT MODIFY. Auto-generated by build_frontend script """
|
""" DO NOT MODIFY. Auto-generated by build_frontend script """
|
||||||
VERSION = "c11382dc4f1efd426f94d77cf498b954"
|
VERSION = "4ae370eaaad6bc779d08713b79ce3cba"
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
|||||||
Subproject commit 75cc118cb121f10cd2e4dd98c9b99ce1219c485a
|
Subproject commit 4cdefac2fe6f016fa09d872c8cb062ba01442b08
|
Loading…
x
Reference in New Issue
Block a user