Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
b5b509d
Initial working commit
oblogic7 Feb 16, 2019
9107f4c
Create const file. Load camera from component.
oblogic7 Feb 16, 2019
04427a9
Handle failed authentication. Bump library version.
oblogic7 Feb 16, 2019
74b39c4
Remove line break
oblogic7 Feb 16, 2019
37cd298
Camera attributes and recording services
oblogic7 Feb 16, 2019
e88efcc
Merge branch 'dev' of https://github.com/home-assistant/home-assistan…
oblogic7 Jan 25, 2020
d2fe4f6
Add services, manifest, constant update, and exclude_channels. Prefi…
oblogic7 Jan 26, 2020
af19a6e
Update codeowners
oblogic7 Jan 26, 2020
3e52766
Update coveragerc
oblogic7 Jan 26, 2020
c70fc28
Merge branch 'dev' of https://github.com/home-assistant/home-assistan…
oblogic7 Jan 26, 2020
a003f5c
Merge branch 'dev' of https://github.com/home-assistant/home-assistan…
oblogic7 Jan 26, 2020
f30e36a
Remove codeowners line
oblogic7 Jan 26, 2020
d8bc8dc
Update codeowners again from python3 -m script.hassfest
oblogic7 Jan 26, 2020
79e2b44
Merge branch 'dev' of https://github.com/home-assistant/home-assistan…
oblogic7 Jan 31, 2020
0202d8a
Update homeassistant/components/qvrpro/__init__.py
oblogic7 Feb 3, 2020
99d067c
Requested changes
oblogic7 Feb 3, 2020
15e278c
Merge branch 'qvrpro' of https://github.com/oblogic7/home-assistant i…
oblogic7 Feb 3, 2020
d337632
Fix typo
oblogic7 Feb 4, 2020
1bbd804
Update to use exception. Bump library version.
oblogic7 Feb 7, 2020
d5bc4e8
Support stream component
oblogic7 Feb 7, 2020
f2e26ed
Merge branch 'qvrpro' of https://github.com/oblogic7/home-assistant i…
oblogic7 Feb 8, 2020
ede446b
Update module header
oblogic7 Feb 8, 2020
bdb7b94
Missing property wrapper
oblogic7 Feb 8, 2020
4accc26
Partial requested changes
oblogic7 Feb 19, 2020
3b3f65b
Update coveragerc and codeowners
oblogic7 Feb 19, 2020
c1da03b
Move constants to const file. Add SHORT_NAME
oblogic7 Feb 19, 2020
366f535
Add conf variable
oblogic7 Feb 19, 2020
90a27e9
Use camera domain
oblogic7 Feb 19, 2020
bb63e68
More requested changes
oblogic7 Feb 19, 2020
6f887ca
Requested changes
oblogic7 Feb 20, 2020
a0f1d29
Requested changes
oblogic7 Feb 20, 2020
33bb74d
Merge remote-tracking branch 'upstream/dev' into qvrpro
oblogic7 Feb 20, 2020
0d476b1
Update prefix
oblogic7 Feb 20, 2020
afe1929
Handle error condition when camera is not configured to support live …
oblogic7 Feb 20, 2020
31e5fc2
Move method to camera setup. Disable stream component support.
oblogic7 Feb 21, 2020
e072e6d
Merge branch 'dev' of https://github.com/home-assistant/home-assistan…
oblogic7 Feb 21, 2020
e7ee71e
Move auth string to library to prevent private member access
oblogic7 Feb 21, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,7 @@ omit =
homeassistant/components/qnap/sensor.py
homeassistant/components/qrcode/image_processing.py
homeassistant/components/quantum_gateway/device_tracker.py
homeassistant/components/qvr_pro/*
homeassistant/components/qwikswitch/*
homeassistant/components/rachio/*
homeassistant/components/radarr/sensor.py
Expand Down
1 change: 1 addition & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ homeassistant/components/pvoutput/* @fabaff
homeassistant/components/qld_bushfire/* @exxamalte
homeassistant/components/qnap/* @colinodell
homeassistant/components/quantum_gateway/* @cisasteelersfan
homeassistant/components/qvr_pro/* @oblogic7
homeassistant/components/qwikswitch/* @kellerza
homeassistant/components/rainbird/* @konikvranik
homeassistant/components/raincloud/* @vanstinator
Expand Down
100 changes: 100 additions & 0 deletions homeassistant/components/qvr_pro/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"""Support for QVR Pro NVR software by QNAP."""

import logging

from pyqvrpro import Client
from pyqvrpro.client import AuthenticationError, InsufficientPermissionsError
import voluptuous as vol

from homeassistant.components.camera import DOMAIN as CAMERA_DOMAIN
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.discovery import load_platform

from .const import (
CONF_EXCLUDE_CHANNELS,
DOMAIN,
SERVICE_START_RECORD,
SERVICE_STOP_RECORD,
)

SERVICE_CHANNEL_GUID = "guid"

_LOGGER = logging.getLogger(__name__)

CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.Schema(
{
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_EXCLUDE_CHANNELS, default=[]): vol.All(
cv.ensure_list_csv, [cv.positive_int]
),
}
)
},
extra=vol.ALLOW_EXTRA,
)

SERVICE_CHANNEL_RECORD_SCHEMA = vol.Schema(
{vol.Required(SERVICE_CHANNEL_GUID): cv.string}
)


def setup(hass, config):
"""Set up the QVR Pro component."""
conf = config[DOMAIN]
user = conf[CONF_USERNAME]
password = conf[CONF_PASSWORD]
host = conf[CONF_HOST]
excluded_channels = conf[CONF_EXCLUDE_CHANNELS]

try:
qvrpro = Client(user, password, host)

channel_resp = qvrpro.get_channel_list()

except InsufficientPermissionsError:
_LOGGER.error("User must have Surveillance Management permission")
return False
except AuthenticationError:
_LOGGER.error("Authentication failed")
return False

channels = []

for channel in channel_resp["channels"]:
if channel["channel_index"] + 1 in excluded_channels:
continue

channels.append(channel)

hass.data[DOMAIN] = {"channels": channels, "client": qvrpro}

load_platform(hass, CAMERA_DOMAIN, DOMAIN, {}, config)

# Register services
def handle_start_record(call):
guid = call.data[SERVICE_CHANNEL_GUID]
qvrpro.start_recording(guid)

def handle_stop_record(call):
guid = call.data[SERVICE_CHANNEL_GUID]
qvrpro.stop_recording(guid)

hass.services.register(
DOMAIN,
SERVICE_START_RECORD,
handle_start_record,
schema=SERVICE_CHANNEL_RECORD_SCHEMA,
)
hass.services.register(
DOMAIN,
SERVICE_STOP_RECORD,
handle_stop_record,
schema=SERVICE_CHANNEL_RECORD_SCHEMA,
)

return True
102 changes: 102 additions & 0 deletions homeassistant/components/qvr_pro/camera.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
"""Support for QVR Pro streams."""

import logging

from pyqvrpro.client import QVRResponseError

from homeassistant.components.camera import Camera

from .const import DOMAIN, SHORT_NAME

_LOGGER = logging.getLogger(__name__)


def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the QVR Pro camera platform."""
if discovery_info is None:
return

client = hass.data[DOMAIN]["client"]
Comment thread
oblogic7 marked this conversation as resolved.

entities = []

for channel in hass.data[DOMAIN]["channels"]:

stream_source = get_stream_source(channel["guid"], client)
entities.append(
QVRProCamera(**channel, stream_source=stream_source, client=client)
)

add_entities(entities)


def get_stream_source(guid, client):
"""Get channel stream source."""
try:
resp = client.get_channel_live_stream(guid, protocol="rtsp")

full_url = resp["resourceUris"]

protocol = full_url[:7]
auth = f"{client.get_auth_string()}@"
url = full_url[7:]

return f"{protocol}{auth}{url}"

except QVRResponseError as ex:
_LOGGER.error(ex)
return None


class QVRProCamera(Camera):
"""Representation of a QVR Pro camera."""

def __init__(self, name, model, brand, channel_index, guid, stream_source, client):
"""Init QVR Pro camera."""

self._name = f"{SHORT_NAME} {name}"
self._model = model
self._brand = brand
self.index = channel_index
self.guid = guid
self._client = client
self._stream_source = stream_source

self._supported_features = 0

super().__init__()

@property
def name(self):
"""Return the name of the entity."""
return self._name

@property
def model(self):
"""Return the model of the entity."""
return self._model

@property
def brand(self):
"""Return the brand of the entity."""
return self._brand

@property
def device_state_attributes(self):
"""Get the state attributes."""
attrs = {"qvr_guid": self.guid}

return attrs

def camera_image(self):
"""Get image bytes from camera."""
return self._client.get_snapshot(self.guid)

async def stream_source(self):
"""Get stream source."""
return self._stream_source

@property
def supported_features(self):
"""Get supported features."""
return self._supported_features
9 changes: 9 additions & 0 deletions homeassistant/components/qvr_pro/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""Constants for QVR Pro component."""

DOMAIN = "qvr_pro"
SHORT_NAME = "QVR"

CONF_EXCLUDE_CHANNELS = "exclude_channels"

SERVICE_STOP_RECORD = "stop_record"
SERVICE_START_RECORD = "start_record"
8 changes: 8 additions & 0 deletions homeassistant/components/qvr_pro/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"domain": "qvr_pro",
"name": "QVR Pro",
"documentation": "https://www.home-assistant.io/integrations/qvr_pro",
"requirements": ["pyqvrpro==0.51"],
"dependencies": [],
"codeowners": ["@oblogic7"]
}
13 changes: 13 additions & 0 deletions homeassistant/components/qvr_pro/services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
start_record:
description: Start QVR Pro recording on specified channel.
fields:
guid:
description: GUID of the channel to start recording.
example: '245EBE933C0A597EBE865C0A245E0002'

stop_record:
description: Stop QVR Pro recording on specified channel.
fields:
guid:
description: GUID of the channel to stop recording.
example: '245EBE933C0A597EBE865C0A245E0002'
3 changes: 3 additions & 0 deletions requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1462,6 +1462,9 @@ pypoint==1.1.2
# homeassistant.components.ps4
pyps4-2ndscreen==1.0.7

# homeassistant.components.qvr_pro
pyqvrpro==0.51

# homeassistant.components.qwikswitch
pyqwikswitch==0.93

Expand Down