The NVR tells us the admin username, but not the password for the camera. Right now, we assume the default password, which obviously doesn't work for people that have changed it. The uvcclient library provides a way to set the cached admin password for a camera, which is stored in a client-specific location. We can utilize that to grab the password, falling back to the default if it's unset. With this, people just need to run a command per camera to set the admin password on their systems, if it has changed.
142 lines
4.3 KiB
Python
142 lines
4.3 KiB
Python
"""
|
|
homeassistant.components.camera.uvc
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
Support for Ubiquiti's UVC cameras.
|
|
|
|
For more details about this platform, please refer to the documentation at
|
|
https://home-assistant.io/components/camera.uvc/
|
|
"""
|
|
import logging
|
|
import socket
|
|
|
|
import requests
|
|
|
|
from homeassistant.components.camera import DOMAIN, Camera
|
|
from homeassistant.helpers import validate_config
|
|
|
|
REQUIREMENTS = ['uvcclient==0.8']
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
|
""" Discover cameras on a Unifi NVR. """
|
|
if not validate_config({DOMAIN: config}, {DOMAIN: ['nvr', 'key']},
|
|
_LOGGER):
|
|
return None
|
|
|
|
addr = config.get('nvr')
|
|
port = int(config.get('port', 7080))
|
|
key = config.get('key')
|
|
|
|
from uvcclient import nvr
|
|
nvrconn = nvr.UVCRemote(addr, port, key)
|
|
try:
|
|
cameras = nvrconn.index()
|
|
except nvr.NotAuthorized:
|
|
_LOGGER.error('Authorization failure while connecting to NVR')
|
|
return False
|
|
except nvr.NvrError:
|
|
_LOGGER.error('NVR refuses to talk to me')
|
|
return False
|
|
except requests.exceptions.ConnectionError as ex:
|
|
_LOGGER.error('Unable to connect to NVR: %s', str(ex))
|
|
return False
|
|
|
|
for camera in cameras:
|
|
add_devices([UnifiVideoCamera(nvrconn,
|
|
camera['uuid'],
|
|
camera['name'])])
|
|
|
|
|
|
class UnifiVideoCamera(Camera):
|
|
""" A Ubiquiti Unifi Video Camera. """
|
|
|
|
def __init__(self, nvr, uuid, name):
|
|
super(UnifiVideoCamera, self).__init__()
|
|
self._nvr = nvr
|
|
self._uuid = uuid
|
|
self._name = name
|
|
self.is_streaming = False
|
|
self._connect_addr = None
|
|
self._camera = None
|
|
|
|
@property
|
|
def name(self):
|
|
return self._name
|
|
|
|
@property
|
|
def is_recording(self):
|
|
caminfo = self._nvr.get_camera(self._uuid)
|
|
return caminfo['recordingSettings']['fullTimeRecordEnabled']
|
|
|
|
@property
|
|
def brand(self):
|
|
return 'Ubiquiti'
|
|
|
|
@property
|
|
def model(self):
|
|
caminfo = self._nvr.get_camera(self._uuid)
|
|
return caminfo['model']
|
|
|
|
def _login(self):
|
|
from uvcclient import camera as uvc_camera
|
|
from uvcclient import store as uvc_store
|
|
|
|
caminfo = self._nvr.get_camera(self._uuid)
|
|
if self._connect_addr:
|
|
addrs = [self._connect_addr]
|
|
else:
|
|
addrs = [caminfo['host'], caminfo['internalHost']]
|
|
|
|
store = uvc_store.get_info_store()
|
|
password = store.get_camera_password(self._uuid)
|
|
if password is None:
|
|
_LOGGER.debug('Logging into camera %(name)s with default password',
|
|
dict(name=self._name))
|
|
password = 'ubnt'
|
|
|
|
camera = None
|
|
for addr in addrs:
|
|
try:
|
|
camera = uvc_camera.UVCCameraClient(addr,
|
|
caminfo['username'],
|
|
password)
|
|
camera.login()
|
|
_LOGGER.debug('Logged into UVC camera %(name)s via %(addr)s',
|
|
dict(name=self._name, addr=addr))
|
|
self._connect_addr = addr
|
|
except socket.error:
|
|
pass
|
|
except uvc_camera.CameraConnectError:
|
|
pass
|
|
except uvc_camera.CameraAuthError:
|
|
pass
|
|
if not camera:
|
|
_LOGGER.error('Unable to login to camera')
|
|
return None
|
|
|
|
self._camera = camera
|
|
return True
|
|
|
|
def camera_image(self):
|
|
from uvcclient import camera as uvc_camera
|
|
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)
|
|
else:
|
|
_LOGGER.error('Unable to log into camera, unable '
|
|
'to get snapshot')
|
|
raise
|
|
|
|
return _get_image()
|