def test_set_recordmode(self): fake_resp1 = {'data': [{'recordingSettings': { 'fullTimeRecordEnabled': False, 'motionRecordEnabled': False, }}]} fake_resp2 = {'data': [{'recordingSettings': { 'fullTimeRecordEnabled': True, 'motionRecordEnabled': False, 'channel': 1, }}]} def fake_req(path, method='GET', data=None): if method == 'GET': return fake_resp1 elif method == 'PUT': self.assertEqual(json.dumps(fake_resp2['data'][0]), data) return fake_resp2 client = nvr.UVCRemote('foo', 7080, 'key') with mock.patch.object(client, '_uvc_request') as mock_r: mock_r.side_effect = fake_req client.set_recordmode('uuid', 'full', chan='medium') self.assertTrue(mock_r.called) fake_resp2['data'][0]['recordingSettings'] = { 'fullTimeRecordEnabled': False, 'motionRecordEnabled': True, 'channel': 0, } with mock.patch.object(client, '_uvc_request') as mock_r: mock_r.side_effect = fake_req client.set_recordmode('uuid', 'motion', chan='high') self.assertTrue(mock_r.called)
def setup_platform(hass, config, add_entities, discovery_info=None): """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] try: # Exceptions may be raised in all method calls to the nvr library. nvrconn = nvr.UVCRemote(addr, port, key, ssl=ssl) cameras = nvrconn.index() 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 = [ 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 add_entities([ UnifiVideoCamera(nvrconn, camera[identifier], camera["name"], password) for camera in cameras ]) return True
def setup_platform(hass, config, add_devices, discovery_info=None): """Discover cameras on a Unifi NVR.""" addr = config[CONF_NVR] key = config[CONF_KEY] password = config[CONF_PASSWORD] port = config[CONF_PORT] 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 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 = [ camera for camera in cameras if 'airCam' not in nvrconn.get_camera(camera[identifier])['model'] ] add_devices([ UnifiVideoCamera(nvrconn, camera[identifier], camera['name'], password) for camera in cameras ]) return True
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'])])
def test_prune_zones(self): fake_resp = {'data': [{'zones': ['fake-zone1', 'fake-zone2']}]} client = nvr.UVCRemote('foo', 7080, 'key') with mock.patch.object(client, '_uvc_request') as mock_r: mock_r.return_value = fake_resp resp = client.prune_zones('uuid') mock_r.assert_any_call('/api/2.0/camera/uuid', 'PUT', json.dumps({'zones': ['fake-zone1']}))
def test_get_zones(self): fake_resp = {'data': [{'zones': ['fake-zone1', 'fake-zone2']}]} client = nvr.UVCRemote('foo', 7080, 'key') with mock.patch.object(client, '_uvc_request') as mock_r: mock_r.return_value = fake_resp resp = client.list_zones('uuid') mock_r.assert_any_call('/api/2.0/camera/uuid') self.assertEqual(fake_resp['data'][0]['zones'], resp)
def test_uvc_request_failed_noauth(self): client = nvr.UVCRemote('foo', 7080, 'key') conn = httplib.HTTPConnection.return_value resp = conn.getresponse.return_value resp.status = 401 self.assertRaises(nvr.NotAuthorized, client._uvc_request, '/bar', method='PUT', data='foobar')
def test_get_picture_settings(self): fake_resp = {'data': [{'ispSettings': {'settingA': 1, 'settingB': 'foo'}}]} client = nvr.UVCRemote('foo', 7080, 'key') with mock.patch.object(client, '_uvc_request') as mock_r: mock_r.return_value = fake_resp self.assertEqual({'settingA': 1, 'settingB': 'foo'}, client.get_picture_settings('uuid'))
def test_get_snapshot(self): client = nvr.UVCRemote('foo', 7080, 'key') with mock.patch.object(client, '_safe_request') as mock_r: mock_r.return_value.status = 200 mock_r.return_value.read.return_value = 'image' resp = client.get_snapshot('foo') mock_r.assert_called_once_with( 'GET', '/api/2.0/snapshot/camera/foo?force=true&apiKey=key') self.assertEqual('image', resp)
def test_320_returns_uuid(self, mock_index, mock_bootstrap): mock_index.return_value = [{ 'name': mock.sentinel.name, 'uuid': mock.sentinel.uuid, 'id': mock.sentinel.id, }] mock_bootstrap.return_value = {'systemInfo': {'version': '3.2.0'}} client = nvr.UVCRemote('foo', 7080, 'key') self.assertEqual(mock.sentinel.id, client.name_to_uuid(mock.sentinel.name))
def test_set_picture_settings(self): fake_resp = {'data': [{'ispSettings': {'settingA': 1, 'settingB': 'foo'}}]} client = nvr.UVCRemote('foo', 7080, 'key') newvals = {'settingA': 2, 'settingB': 'foo'} with mock.patch.object(client, '_uvc_request') as mock_r: mock_r.return_value = fake_resp resp = client.set_picture_settings('uuid', newvals) mock_r.assert_any_call('/api/2.0/camera/uuid', 'PUT', json.dumps({'ispSettings': newvals})) self.assertEqual(fake_resp['data'][0]['ispSettings'], resp)
def test_uvc_request_get(self): client = nvr.UVCRemote('foo', 7080, 'key') conn = httplib.HTTPConnection.return_value resp = conn.getresponse.return_value resp.status = 200 resp.read.return_value = json.dumps({}).encode() client._uvc_request('/bar') headers = { 'Content-Type': 'application/json', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Accept-Encoding': 'gzip, deflate, sdch', } conn.request.assert_called_once_with('GET', '/bar?apiKey=key', None, headers)
def test_uvc_request_put(self): client = nvr.UVCRemote('foo', 7080, 'key') conn = httplib.HTTPConnection.return_value resp = conn.getresponse.return_value resp.status = 200 resp.read.return_value = json.dumps({}).encode() result = client._uvc_request('/bar?foo=bar', method='PUT', data='foobar') self.assertEqual({}, result) headers = { 'Content-Type': 'application/json', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Accept-Encoding': 'gzip, deflate, sdch', } conn.request.assert_called_once_with('PUT', '/bar?foo=bar&apiKey=key', 'foobar', headers)
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') key = config.get('key') try: port = int(config.get('port', 7080)) except ValueError: _LOGGER.error('Invalid port number provided') return False 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 identifier = nvrconn.server_version >= (3, 2, 0) and 'id' or 'uuid' # Filter out airCam models, which are not supported in the latest # version of UnifiVideo and which are EOL by Ubiquiti cameras = [ camera for camera in cameras if 'airCam' not in nvrconn.get_camera(camera[identifier])['model'] ] add_devices([ UnifiVideoCamera(nvrconn, camera[identifier], camera['name']) for camera in cameras ]) return True
def test_get_snapshot_error(self): client = nvr.UVCRemote('foo', 7080, 'key') with mock.patch.object(client, '_safe_request') as mock_r: mock_r.return_value.status = 401 self.assertRaises(nvr.NvrError, client.get_snapshot, 'foo')
def main(): host, port, apikey, path = nvr.get_auth_from_env() parser = optparse.OptionParser() parser.add_option('-H', '--host', default=host, help='UVC Hostname') parser.add_option('-P', '--port', default=port, type=int, help='UVC Port') parser.add_option('-K', '--apikey', default=apikey, help='UVC API Key') parser.add_option('-v', '--verbose', action='store_true', default=False) parser.add_option('-d', '--dump', action='store_true', default=False) parser.add_option('-u', '--uuid', default=None, help='Camera UUID') parser.add_option('--name', default=None, help='Camera name') parser.add_option('-l', '--list', action='store_true', default=False) parser.add_option('--irsensitivity', default=None, help='IR Camera Sensitivity (low,medium,high)') parser.add_option('--irledmode', default=None, help='IR Led mode (none,full,motion)') parser.add_option('--externalirmode', default=None, help='Recording mode off, on)') parser.add_option('--recordmode', default=None, help='Recording mode (none,full,motion)') parser.add_option('--get-externalirmode', default=None, action='store_true', help='Show if an external IR emitter is on') parser.add_option('--get-irledmode', default=None, action='store_true', help='Show IR detection mode') parser.add_option('--get-irsensitivity', default=None, action='store_true', help='Show IR Camera sensitivity level') parser.add_option('--get-recordmode', default=None, action='store_true', help='Show recording mode') parser.add_option('--recordchannel', default=None, help='Recording channel (high,medium,low)') parser.add_option('-p', '--get-picture-settings', action='store_true', default=False, help='Return picture settings as a string') parser.add_option('--set-picture-settings', default=None, help=('Set picture settings with a string like that ' 'returned from --get-picture-settings')) parser.add_option('--set-led', default=None, metavar='ENABLED', help='Enable/Disable front LED (on,off)') parser.add_option('--get-snapshot', default=None, action='store_true', help='Get a snapshot image and write to stdout') parser.add_option('--prune-zones', default=None, action='store_true', help='Prune all but the first motion zone') parser.add_option('--list-zones', default=None, action='store_true', help='List motion zones') parser.add_option('--set-password', default=None, action='store_true', help='Store camera password') parser.add_option( '--test-login', default=None, action='store_true', help='Test if the given username/password can login to the NVR') parser.add_option('--username', default=None, help='Username to attempt the login with') parser.add_option('--password', default=None, help='Password to attempt the login with') parser.add_option('--get-allalerts', default=None, action='store_true', help='Dump the alerts in the alert table') parser.add_option('--delete-allalerts', default=None, action='store_true', help='Deletes all the alerts in the alert table') parser.add_option( '--delete-alert', action='store_true', help= 'Delete the alert identified by the timestamp or alert-type arguments') parser.add_option('--timestamp', type=int, help='integer timestamp to identify an alert') parser.add_option('--alert-type', default=None, help='type of alert to delete') opts, args = parser.parse_args() if not all([opts.host, opts.port, opts.apikey]): print('Host, port, and apikey are required') return if opts.verbose: level = logging.DEBUG else: level = logging.WARNING logging.basicConfig(level=level) client = nvr.UVCRemote(opts.host, opts.port, opts.apikey) if opts.name: opts.uuid = client.name_to_uuid(opts.name) if not opts.uuid: print('`%s\' is not a valid name' % opts.name) return if opts.dump: client.dump(opts.uuid) elif opts.list: for cam in client.index(): ident = cam[client.camera_identifier] recmode = client.get_recordmode(ident) ip = client.get_cameraipaddress(ident) if not cam['managed']: status = 'new' elif cam['state'] == 'FIRMWARE_OUTDATED': status = 'outdated' elif cam['state'] == 'UPGRADING': status = 'upgrading' elif cam['state'] == 'DISCONNECTED': status = 'offline' elif cam['state'] == 'CONNECTED': status = 'online' else: status = 'unknown:%s' % cam['state'] print('%s: %-24.24s %s [%10s] %s' % (cam['id'], cam['name'], ip, status, recmode)) elif opts.recordmode: if not opts.uuid: print('Name or UUID is required') return 1 r = client.set_recordmode(opts.uuid, opts.recordmode, opts.recordchannel) if r is True: return 0 else: return 1 elif opts.externalirmode: if not opts.uuid: print('Name or UUID is required') return 1 r = client.set_externalirmode(opts.uuid, opts.externalirmode) if r is True: return 0 else: return 1 elif opts.irsensitivity: if not opts.uuid: print('Name or UUID is required') return 1 r = client.set_irsensitivity(opts.uuid, opts.irsensitivity) if r is True: return 0 else: return 1 elif opts.irledmode: if not opts.uuid: print('Name or UUID is required') return 1 r = client.set_irledmode(opts.uuid, opts.irledmode) if r is True: return 0 else: return 1 elif opts.get_recordmode: if not opts.uuid: print('Name or UUID is required') return 1 r = client.get_recordmode(opts.uuid) print(r) return r == 'none' elif opts.get_externalirmode: if not opts.uuid: print('Name or UUID is required') return 1 r = client.get_externalirmode(opts.uuid) print(r) return r == 'none' elif opts.get_irsensitivity: if not opts.uuid: print('Name or UUID is required') return 1 r = client.get_irsensitivity(opts.uuid) print(r) return r == 'none' elif opts.get_irledmode: if not opts.uuid: print('Name or UUID is required') return 1 r = client.get_irledmode(opts.uuid) print(r) return r == 'none' elif opts.get_picture_settings: settings = client.get_picture_settings(opts.uuid) print(','.join(['%s=%s' % (k, v) for k, v in settings.items()])) return 0 elif opts.set_picture_settings: settings = {} try: for setting in opts.set_picture_settings.split(','): k, v = setting.split('=') settings[k] = v except ValueError: print('Invalid picture setting string format') return 1 try: result = client.set_picture_settings(opts.uuid, settings) except Invalid as e: print('Invalid value: %s' % e) return 1 for k in settings: if type(result[k])(settings[k]) != result[k]: print('Rejected: %s' % k) return 0 elif opts.set_led is not None: camera = client.get_camera(opts.uuid) if not camera: print('No such camera') return 1 if 'Micro' not in camera['model']: print('Only micro cameras support LED status') return 2 do_led(camera, opts.set_led.lower() == 'on') elif opts.prune_zones: if not opts.uuid: print('Name or UUID is required') return 1 client.prune_zones(opts.uuid) elif opts.list_zones: if not opts.uuid: print('Name or UUID is required') return 1 zones = client.list_zones(opts.uuid) for zone in zones: print(zone['name']) elif opts.get_snapshot: camera = client.get_camera(opts.uuid) if not camera: print('No such camera') return 1 if hasattr(sys.stdout, 'buffer'): # sys.stdout.buffer.write(do_snapshot(client, camera)) sys.stdout.buffer.write(client.get_snapshot(opts.uuid)) else: sys.stdout.write(do_snapshot(client, camera)) elif opts.set_password: do_set_password(opts) elif opts.get_allalerts: data = client.get_all_alerts() for alert in data: pprint.pprint(alert) elif opts.delete_alert: data = client.get_all_alerts() for alert in data: if opts.timestamp is not None: if alert['timestamp'] == opts.timestamp: alert['alertState'] = 'deleted' if client.delete_alert( alert)['timestamp'] == opts.timestamp: print("Alert Deleted") else: print("Failed to delete alert") if opts.alert_type is not None: if opts.alert_type == str(alert['alertType']): alert['alertState'] = 'deleted' resp = client.delete_alert(alert) if resp['data'][0]['alertType'] == opts.alert_type: print("Alert " + resp['data'][0]['_id'] + " Deleted") else: print("Failed to delete alert") elif opts.delete_allalerts is not None: data = client.get_all_alerts() for alert in data: alert['alertState'] = 'deleted' resp = client.delete_alert(alert) if resp['data'][0]['_id'] == alert['_id']: print("Alert " + resp['data'][0]['_id'] + " Deleted") else: print("Failed to delete alert") data = client.get_all_alerts() if len(data) <= 1: print("All alerts deleted") else: print(str(len(data)) + " alerts remaining following deletion") elif opts.test_login: resp = client.test_login(opts.username, opts.password) if resp.status == 200: print("login successful") return 0 else: print("login failed status=" + str(resp.status) + " error=" + resp.reason) return 1
def main(): host, port, apikey, path = nvr.get_auth_from_env() parser = optparse.OptionParser() parser.add_option('-H', '--host', default=host, help='UVC Hostname') parser.add_option('-P', '--port', default=port, type=int, help='UVC Port') parser.add_option('-K', '--apikey', default=apikey, help='UVC API Key') parser.add_option('-v', '--verbose', action='store_true', default=False) parser.add_option('-d', '--dump', action='store_true', default=False) parser.add_option('-u', '--uuid', default=None, help='Camera UUID') parser.add_option('--name', default=None, help='Camera name') parser.add_option('-l', '--list', action='store_true', default=False) parser.add_option('--recordmode', default=None, help='Recording mode (none,full,motion)') parser.add_option('--get-recordmode', default=None, action='store_true', help='Show recording mode') parser.add_option('--recordchannel', default=None, help='Recording channel (high,medium,low)') parser.add_option('-p', '--get-picture-settings', action='store_true', default=False, help='Return picture settings as a string') parser.add_option('--set-picture-settings', default=None, help=('Set picture settings with a string like that ' 'returned from --get-picture-settings')) parser.add_option('--set-led', default=None, metavar='ENABLED', help='Enable/Disable front LED (on,off)') parser.add_option('--get-snapshot', default=None, action='store_true', help='Get a snapshot image and write to stdout') parser.add_option('--reboot', default=None, action='store_true', help='Reboot camera') parser.add_option('--prune-zones', default=None, action='store_true', help='Prune all but the first motion zone') parser.add_option('--list-zones', default=None, action='store_true', help='List motion zones') parser.add_option('--set-password', default=None, action='store_true', help='Store camera password') opts, args = parser.parse_args() if not all([host, port, apikey]): print('Host, port, and apikey are required') return if opts.verbose: level = logging.DEBUG else: level = logging.WARNING logging.basicConfig(level=level) client = nvr.UVCRemote(opts.host, opts.port, opts.apikey) if opts.name: opts.uuid = client.name_to_uuid(opts.name) if not opts.uuid: print('`%s\' is not a valid name' % opts.name) return if opts.dump: client.dump(opts.uuid) elif opts.list: for cam in client.index(): ident = cam[client.camera_identifier] recmode = client.get_recordmode(ident) if not cam['managed']: status = 'new' elif cam['state'] == 'FIRMWARE_OUTDATED': status = 'outdated' elif cam['state'] == 'UPGRADING': status = 'upgrading' elif cam['state'] == 'DISCONNECTED': status = 'offline' elif cam['state'] == 'CONNECTED': status = 'online' else: status = 'unknown:%s' % cam['state'] print('%s: %-24.24s [%10s] %s' % (cam['uuid'], cam['name'], status, recmode)) elif opts.recordmode: if not opts.uuid: print('Name or UUID is required') return 1 r = client.set_recordmode(opts.uuid, opts.recordmode, opts.recordchannel) if r is True: return 0 else: return 1 elif opts.get_recordmode: if not opts.uuid: print('Name or UUID is required') return 1 r = client.get_recordmode(opts.uuid) print(r) return r == 'none' elif opts.get_picture_settings: settings = client.get_picture_settings(opts.uuid) print(','.join(['%s=%s' % (k, v) for k, v in settings.items()])) return 0 elif opts.set_picture_settings: settings = {} try: for setting in opts.set_picture_settings.split(','): k, v = setting.split('=') settings[k] = v except ValueError: print('Invalid picture setting string format') return 1 try: result = client.set_picture_settings(opts.uuid, settings) except Invalid as e: print('Invalid value: %s' % e) return 1 for k in settings: if type(result[k])(settings[k]) != result[k]: print('Rejected: %s' % k) return 0 elif opts.set_led is not None: camera = client.get_camera(opts.uuid) if not camera: print('No such camera') return 1 if 'Micro' not in camera['model']: print('Only micro cameras support LED status') return 2 do_led(camera, opts.set_led.lower() == 'on') elif opts.prune_zones: if not opts.uuid: print('Name or UUID is required') return 1 client.prune_zones(opts.uuid) elif opts.list_zones: if not opts.uuid: print('Name or UUID is required') return 1 zones = client.list_zones(opts.uuid) for zone in zones: print(zone['name']) elif opts.get_snapshot: camera = client.get_camera(opts.uuid) if not camera: print('No such camera') return 1 if hasattr(sys.stdout, 'buffer'): sys.stdout.buffer.write(do_snapshot(client, camera)) else: sys.stdout.write(do_snapshot(client, camera)) elif opts.reboot: camera = client.get_camera(opts.uuid) if not camera: print('No such camera') return 1 do_reboot(client, camera) elif opts.set_password: do_set_password(opts) else: print('No action specified; try --help')
def test_bootstrap_server_version(self, mock_bootstrap): mock_bootstrap.return_value = {'systemInfo': {'version': '3.4.beta5'}} client = nvr.UVCRemote('foo', 7080, 'key') self.assertEqual((3, 4, 0), client.server_version)