Clean up camera component

This commit is contained in:
Paulus Schoutsen 2015-07-10 23:17:12 -07:00
parent 703266312e
commit aec25c88b4
2 changed files with 54 additions and 167 deletions

View File

@ -5,24 +5,23 @@ homeassistant.components.camera
Component to interface with various cameras.
The following features are supported:
-Recording
-Snapshot
-Motion Detection Recording(for supported cameras)
-Automatic Configuration(for supported cameras)
-Creation of child entities for supported functions
-Collating motion event images passed via FTP into time based events
-Returning recorded camera images and streams
-Proxying image requests via HA for external access
-Converting a still image url into a live video stream
-A service for calling camera functions
- Returning recorded camera images and streams
- Proxying image requests via HA for external access
- Converting a still image url into a live video stream
Upcoming features
-Camera movement(panning)
-Zoom
-Light/Nightvision toggling
-Support for more devices
-A demo entity
-Expanded documentation
- Recording
- Snapshot
- Motion Detection Recording(for supported cameras)
- Automatic Configuration(for supported cameras)
- Creation of child entities for supported functions
- Collating motion event images passed via FTP into time based events
- A service for calling camera functions
- Camera movement(panning)
- Zoom
- Light/Nightvision toggling
- Support for more devices
- Expanded documentation
"""
import requests
import logging
@ -103,7 +102,7 @@ def setup(hass, config):
camera = component.entities[entity_id]
if camera:
response = camera.get_camera_image()
response = camera.camera_image()
handler.wfile.write(response)
else:
handler.send_response(HTTP_NOT_FOUND)
@ -146,7 +145,7 @@ def setup(hass, config):
while True:
img_bytes = camera.get_camera_image()
img_bytes = camera.camera_image()
headers_str = '\r\n'.join((
'Content-length: {}'.format(len(img_bytes)),
@ -180,23 +179,15 @@ def setup(hass, config):
class Camera(Entity):
""" The base class for camera components """
def __init__(self):
self.is_streaming = False
@property
# pylint: disable=no-self-use
def is_recording(self):
""" Returns true if the device is recording """
return False
@property
# pylint: disable=no-self-use
def is_streaming(self):
""" Returns true if the device is streaming """
return False
@is_streaming.setter
def is_streaming(self, value):
""" Set this to true when streaming begins """
pass
@property
# pylint: disable=no-self-use
def brand(self):
@ -209,19 +200,7 @@ class Camera(Entity):
""" Returns string of camera model """
return None
@property
# pylint: disable=no-self-use
def image_url(self):
""" Return the still image segment of the URL """
return None
@property
# pylint: disable=no-self-use
def still_image_url(self):
""" Get the URL of a camera still image """
return None
def get_camera_image(self):
def camera_image(self):
""" Return bytes of camera image """
raise NotImplementedError()
@ -238,14 +217,11 @@ class Camera(Entity):
@property
def state_attributes(self):
""" Returns optional state attributes. """
attr = super().state_attributes
attr['model_name'] = self.model
attr['brand'] = self.brand
CAMERA_PROXY_URL.format(self.entity_id)
attr['still_image_url'] = CAMERA_STILL_URL.format(self.entity_id)
attr[ATTR_ENTITY_PICTURE] = ENTITY_IMAGE_URL.format(
self.entity_id,
str(time.time()))
attr['stream_url'] = CAMERA_PROXY_URL.format(self.entity_id)
return attr
return {
'model_name': self.model,
'brand': self.brand,
'still_image_url': CAMERA_STILL_URL.format(self.entity_id),
ATTR_ENTITY_PICTURE: ENTITY_IMAGE_URL.format(
self.entity_id, str(time.time())),
'stream_url': CAMERA_PROXY_URL.format(self.entity_id)
}

View File

@ -1,76 +1,45 @@
"""
Support for IP Cameras.
This component provides basic support for IP camera models that do not have
a speicifc HA component.
This component provides basic support for IP cameras. For the basic support to
work you camera must support accessing a JPEG snapshot via a URL and you will
need to specify the "still_image_url" parameter which should be the location of
the JPEG image.
As part of the basic support the following features will be provided:
-MJPEG video streaming
-Saving a snapshot
-Recording(JPEG frame capture)
NOTE: for the basic support to work you camera must support accessing a JPEG
snapshot via a URL and you will need to specify the "still_image_url" parameter
which should be the location of the JPEG snapshot relative to you specified
base_url. For example "snapshot.cgi" or "image.jpg".
To use this component you will need to add something like the following to your
config/configuration.yaml
To use this component, add the following to your config/configuration.yaml:
camera:
platform: generic
base_url: http://YOUR_CAMERA_IP_AND_PORT/
name: Door Camera
brand: dlink
family: DCS
model: DCS-930L
username: YOUR_USERNAME
password: YOUR_PASSWORD
still_image_url: image.jpg
still_image_url: http://YOUR_CAMERA_IP_AND_PORT/image.jpg
VARIABLES:
These are the variables for the device_data array:
base_url
still_image_url
*Required
The base URL for accessing you camera
The URL your camera serves the image on.
Example: http://192.168.1.21:2112/
name
*Optional
This parameter allows you to override the name of your camera in homeassistant
brand
*Optional
The manufacturer of your device, used to help load the specific camera
functionality.
family
*Optional
The family of devices by the specified brand, useful when many models
support the same settings. This used when attempting load up specific
device functionality.
model
*Optional
The specific model number of your device.
still_image_url
*Optional
Useful if using an unsupported camera model. This should point to the location
of the still image on your particular camera and should be relative to your
specified base_url.
Example: cam/image.jpg
username
*Required
*Optional
THe username for acessing your camera
password
*Required
*Optional
the password for accessing your camera
@ -88,97 +57,39 @@ _LOGGER = logging.getLogger(__name__)
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Find and return Vera lights. """
if not validate_config(
{DOMAIN: config},
{DOMAIN: ['base_url', CONF_USERNAME, CONF_PASSWORD]},
_LOGGER):
""" Adds a generic IP Camera. """
if not validate_config({DOMAIN: config}, {DOMAIN: ['still_image_url']}, _LOGGER):
return None
camera = GenericCamera(hass, config)
cameras = [camera]
add_devices_callback(cameras)
add_devices_callback([GenericCamera(config)])
# pylint: disable=too-many-instance-attributes
class GenericCamera(Camera):
"""
Base class for cameras.
This is quite a large class but the camera component encompasses a lot of
functionality. It should take care of most of the heavy lifting and
plumbing associated with adding support for additional models of camera.
If you are adding support for a new camera your entity class should inherit
from this.
A generic implementation of an IP camera that is reachable over a URL.
"""
def __init__(self, hass, device_info):
self.hass = hass
self._device_info = device_info
self._base_url = device_info.get('base_url')
if not self._base_url.endswith('/'):
self._base_url = self._base_url + '/'
def __init__(self, device_info):
super().__init__()
self._name = device_info.get('name', 'Generic Camera')
self._username = device_info.get('username')
self._password = device_info.get('password')
self._is_streaming = False
self._still_image_url = device_info.get('still_image_url', 'image.jpg')
self._logger = logging.getLogger(__name__)
def get_camera_image(self):
self._still_image_url += device_info.get('still_image_url', 'image.jpg')
def camera_image(self):
""" Return a still image reponse from the camera """
if self.username and self.password:
if self._username and self._password:
response = requests.get(
self.still_image_url,
auth=HTTPBasicAuth(
self.username,
self.password))
self._still_image_url,
auth=HTTPBasicAuth(self._username,self._password))
else:
response = requests.get(self.still_image_url)
response = requests.get(self._still_image_url)
return response.content
@property
def device_info(self):
""" Return the config data for this device """
return self._device_info
@property
def name(self):
""" Return the name of this device """
return self._device_info.get('name') or super().name
@property
def state_attributes(self):
""" Returns optional state attributes. """
attr = super().state_attributes
return attr
@property
def base_url(self):
""" Return the URL of the IP Camera """
return self._base_url
@property
def username(self):
""" Return the configured username """
return self._username
@property
def password(self):
""" Return the configured password """
return self._password
@property
def is_streaming(self):
return self._is_streaming
@is_streaming.setter
# pylint: disable=arguments-differ
def is_streaming(self, value):
self._is_streaming = value
@property
def still_image_url(self):
""" This should be implemented by different camera models. """
return self.base_url + self._still_image_url
return self._name