core/homeassistant/components/uvc/camera.py

206 lines
6.2 KiB
Python
Raw Normal View History

"""Support for Ubiquiti's UVC cameras."""
import logging
import socket
import requests
import voluptuous as vol
from homeassistant.const import CONF_PORT, CONF_SSL
from homeassistant.components.camera import Camera, PLATFORM_SCHEMA
import homeassistant.helpers.config_validation as cv
from homeassistant.exceptions import PlatformNotReady
_LOGGER = logging.getLogger(__name__)
2019-07-31 19:25:30 +00:00
CONF_NVR = "nvr"
CONF_KEY = "key"
CONF_PASSWORD = "password"
2019-07-31 19:25:30 +00:00
DEFAULT_PASSWORD = "ubnt"
DEFAULT_PORT = 7080
DEFAULT_SSL = False
2019-07-31 19:25:30 +00:00
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_NVR): cv.string,
vol.Required(CONF_KEY): cv.string,
vol.Optional(CONF_PASSWORD, default=DEFAULT_PASSWORD): cv.string,
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean,
}
)
def setup_platform(hass, config, add_entities, discovery_info=None):
2016-03-07 16:45:06 +00:00
"""Discover cameras on a Unifi NVR."""
addr = config[CONF_NVR]
key = config[CONF_KEY]
password = config[CONF_PASSWORD]
port = config[CONF_PORT]
ssl = config[CONF_SSL]
from uvcclient import nvr
2019-07-31 19:25:30 +00:00
try:
# Exceptions may be raised in all method calls to the nvr library.
nvrconn = nvr.UVCRemote(addr, port, key, ssl=ssl)
cameras = nvrconn.index()
2019-07-31 19:25:30 +00:00
identifier = "id" if nvrconn.server_version >= (3, 2, 0) else "uuid"
# Filter out airCam models, which are not supported in the latest
# version of UnifiVideo and which are EOL by Ubiquiti
cameras = [
2019-07-31 19:25:30 +00:00
camera
for camera in cameras
if "airCam" not in nvrconn.get_camera(camera[identifier])["model"]
]
except nvr.NotAuthorized:
_LOGGER.error("Authorization failure while connecting to NVR")
return False
except nvr.NvrError as ex:
_LOGGER.error("NVR refuses to talk to me: %s", str(ex))
raise PlatformNotReady
except requests.exceptions.ConnectionError as ex:
_LOGGER.error("Unable to connect to NVR: %s", str(ex))
raise PlatformNotReady
2019-07-31 19:25:30 +00:00
add_entities(
[
UnifiVideoCamera(nvrconn, camera[identifier], camera["name"], password)
for camera in cameras
]
)
return True
class UnifiVideoCamera(Camera):
2016-03-07 16:45:06 +00:00
"""A Ubiquiti Unifi Video Camera."""
2016-03-07 19:29:54 +00:00
def __init__(self, nvr, uuid, name, password):
2016-03-07 19:29:54 +00:00
"""Initialize an Unifi camera."""
super(UnifiVideoCamera, self).__init__()
self._nvr = nvr
self._uuid = uuid
self._name = name
self._password = password
self.is_streaming = False
self._connect_addr = None
self._camera = None
self._motion_status = False
@property
def name(self):
2016-03-07 16:45:06 +00:00
"""Return the name of this camera."""
return self._name
@property
def is_recording(self):
2016-03-07 16:45:06 +00:00
"""Return true if the camera is recording."""
caminfo = self._nvr.get_camera(self._uuid)
2019-07-31 19:25:30 +00:00
return caminfo["recordingSettings"]["fullTimeRecordEnabled"]
@property
def motion_detection_enabled(self):
"""Camera Motion Detection Status."""
caminfo = self._nvr.get_camera(self._uuid)
2019-07-31 19:25:30 +00:00
return caminfo["recordingSettings"]["motionRecordEnabled"]
@property
def brand(self):
2016-03-07 16:45:06 +00:00
"""Return the brand of this camera."""
2019-07-31 19:25:30 +00:00
return "Ubiquiti"
@property
def model(self):
2016-03-07 16:45:06 +00:00
"""Return the model of this camera."""
caminfo = self._nvr.get_camera(self._uuid)
2019-07-31 19:25:30 +00:00
return caminfo["model"]
def _login(self):
2016-03-07 16:45:06 +00:00
"""Login to the camera."""
from uvcclient import camera as uvc_camera
caminfo = self._nvr.get_camera(self._uuid)
if self._connect_addr:
addrs = [self._connect_addr]
else:
2019-07-31 19:25:30 +00:00
addrs = [caminfo["host"], caminfo["internalHost"]]
if self._nvr.server_version >= (3, 2, 0):
client_cls = uvc_camera.UVCCameraClientV320
else:
client_cls = uvc_camera.UVCCameraClient
2019-07-31 19:25:30 +00:00
if caminfo["username"] is None:
caminfo["username"] = "ubnt"
camera = None
for addr in addrs:
try:
2019-07-31 19:25:30 +00:00
camera = client_cls(addr, caminfo["username"], self._password)
camera.login()
2019-07-31 19:25:30 +00:00
_LOGGER.debug(
"Logged into UVC camera %(name)s via %(addr)s",
dict(name=self._name, addr=addr),
)
self._connect_addr = addr
break
except socket.error:
pass
except uvc_camera.CameraConnectError:
pass
except uvc_camera.CameraAuthError:
pass
if not self._connect_addr:
_LOGGER.error("Unable to login to camera")
return None
self._camera = camera
return True
def camera_image(self):
2016-03-07 16:45:06 +00:00
"""Return the image of this camera."""
from uvcclient import camera as uvc_camera
2019-07-31 19:25:30 +00:00
if not self._camera:
if not self._login():
return
def _get_image(retry=True):
try:
return self._camera.get_snapshot()
except uvc_camera.CameraConnectError:
_LOGGER.error("Unable to contact camera")
except uvc_camera.CameraAuthError:
if retry:
self._login()
return _get_image(retry=False)
2019-07-31 19:25:30 +00:00
_LOGGER.error("Unable to log into camera, unable to get snapshot")
raise
return _get_image()
def set_motion_detection(self, mode):
"""Set motion detection on or off."""
from uvcclient.nvr import NvrError
2019-07-31 19:25:30 +00:00
if mode is True:
2019-07-31 19:25:30 +00:00
set_mode = "motion"
else:
2019-07-31 19:25:30 +00:00
set_mode = "none"
try:
self._nvr.set_recordmode(self._uuid, set_mode)
self._motion_status = mode
except NvrError as err:
_LOGGER.error("Unable to set recordmode to %s", set_mode)
_LOGGER.debug(err)
def enable_motion_detection(self):
"""Enable motion detection in camera."""
self.set_motion_detection(True)
def disable_motion_detection(self):
"""Disable motion detection in camera."""
self.set_motion_detection(False)