10000 Synology SSL fix & Error handling by pvizeli · Pull Request #4325 · home-assistant/core · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Synology SSL fix & Error handling #4325

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Nov 11, 2016
Merged
Changes from all commits
Commits
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
104 changes: 54 additions & 50 deletions homeassistant/components/camera/synology.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@

import voluptuous as vol

import aiohttp
from aiohttp import web
from aiohttp.web_exceptions import HTTPGatewayTimeout
import async_timeout

from homeassistant.const import (
CONF_NAME, CONF_USERNAME, CONF_PASSWORD,
CONF_URL, CONF_WHITELIST, CONF_VERIFY_SSL)
CONF_URL, CONF_WHITELIST, CONF_VERIFY_SSL, EVENT_HOMEASSISTANT_STOP)
from homeassistant.components.camera import (
Camera, PLATFORM_SCHEMA)
import homeassistant.helpers.config_validation as cv
Expand Down Expand Up @@ -58,8 +59,14 @@
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
"""Setup a Synology IP Camera."""
if not config.get(CONF_VERIFY_SSL):
_LOGGER.warning('SSL verification currently cannot be disabled. '
'See https://goo.gl/1h1119')
connector = aiohttp.TCPConnector(verify_ssl=False)
else:
connector = None

websession_init = aiohttp.ClientSession(
loop=hass.loop,
connector=connector
)

# Determine API to use for authentication
syno_api_url = SYNO_API_URL.format(
Expand All @@ -73,12 +80,12 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
}
try:
with async_timeout.timeout(TIMEOUT, loop=hass.loop):
query_req = yield from hass.websession.get(
query_req = yield from websession_init.get(
syno_api_url,
params=query_payload,
params=query_payload
)
except asyncio.TimeoutError:
_LOGGER.error("Timeout on %s", syno_api_url)
except (asyncio.TimeoutError, aiohttp.errors.ClientError):
_LOGGER.exception("Error on %s", syno_api_url)
return False

query_resp = yield from query_req.json()
Expand All @@ -96,12 +103,26 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):

session_id = yield from get_session_id(
hass,
websession_init,
config.get(CONF_USERNAME),
config.get(CONF_PASSWORD),
syno_auth_url,
config.get(CONF_VERIFY_SSL)
syno_auth_url
)

websession_init.detach()

# init websession
websession = aiohttp.ClientSession(
loop=hass.loop, connector=connector, cookies={'id': session_id})

@asyncio.coroutine
def _async_close_websession(event):
"""Close webssesion on shutdown."""
yield from websession.close()

hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_STOP, _async_close_websession)

# Use SessionID to get cameras in system
syno_camera_url = SYNO_API_URL.format(
config.get(CONF_URL), WEBAPI_PATH, camera_api)
Expand All @@ -113,13 +134,12 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
}
try:
with async_timeout.timeout(TIMEOUT, loop=hass.loop):
camera_req = yield from hass.websession.get(
camera_req = yield from websession.get(
syno_camera_url,
params=camera_payload,
cookies={'id': session_id}
params=camera_payload
)
except asyncio.TimeoutError:
_LOGGER.error("Timeout on %s", syno_camera_url)
except (asyncio.TimeoutError, aiohttp.errors.ClientError):
_LOGGER.exception("Error on %s", syno_camera_url)
return False

camera_resp = yield from camera_req.json()
Expand All @@ -128,13 +148,14 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):

# add cameras
devices = []
tasks = []
for camera in cameras:
if not config.get(CONF_WHITELIST):
camera_id = camera['id']
snapshot_path = camera['snapshot_path']

device = SynologyCamera(
hass,
websession,
config,
camera_id,
camera['name'],
Expand All @@ -143,15 +164,13 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
camera_path,
auth_path
)
tasks.append(device.async_read_sid())
devices.append(device)

yield from asyncio.wait(tasks, loop=hass.loop)
yield from async_add_devices(devices)


@asyncio.coroutine
def get_session_id(hass, username, password, login_url, valid_cert):
def get_session_id(hass, websession, username, password, login_url):
"""Get a session id."""
auth_payload = {
'api': AUTH_API,
Expand All @@ -164,12 +183,12 @@ def get_session_id(hass, username, password, login_url, valid_cert):
}
try:
with async_timeout.timeout(TIMEOUT, loop=hass.loop):
auth_req = yield from hass.websession.get(
auth_req = yield from websession.get(
login_url,
params=auth_payload,
params=auth_payload
)
except asyncio.TimeoutError:
_LOGGER.error("Timeout on %s", login_url)
except (asyncio.TimeoutError, aiohttp.errors.ClientError):
_LOGGER.exception("Error on %s", login_url)
return False

auth_resp = yield from auth_req.json()
Expand All @@ -181,36 +200,22 @@ def get_session_id(hass, username, password, login_url, valid_cert):
class SynologyCamera(Camera):
"""An implementation of a Synology NAS based IP camera."""

def __init__(self, config, camera_id, camera_name,
snapshot_path, streaming_path, camera_path, auth_path):
def __init__(self, hass, websession, config, camera_id,
camera_name, snapshot_path, streaming_path, camera_path,
auth_path):
"""Initialize a Synology Surveillance Station camera."""
super().__init__()
self.hass = hass
self._websession = websession
self._name = camera_name
self._username = config.get(CONF_USERNAME)
self._password = config.get(CONF_PASSWORD)
self._synology_url = config.get(CONF_URL)
self._api_url = config.get(CONF_URL) + 'webapi/'
self._login_url = config.get(CONF_URL) + '/webapi/' + 'auth.cgi'
self._camera_name = config.get(CONF_CAMERA_NAME)
self._stream_id = config.get(CONF_STREAM_ID)
self._valid_cert = config.get(CONF_VERIFY_SSL)
self._camera_id = camera_id
self._snapshot_path = snapshot_path
self._streaming_path = streaming_path
self._camera_path = camera_path
self._auth_path = auth_path
self._session_id = None

@asyncio.coroutine
def async_read_sid(self):
"""Get a session id."""
self._session_id = yield from get_session_id(
self.hass,
self._username,
self._password,
self._login_url,
self._valid_cert
)

def camera_image(self):
"""Return bytes of camera image.&q A2F7 uot;""
Expand All @@ -231,13 +236,12 @@ def async_camera_image(self):
}
try:
with async_timeout.timeout(TIMEOUT, loop=self.hass.loop):
response = yield from self.hass.websession.get(
response = yield from self._websession.get(
image_url,
params=image_payload,
cookies={'id': self._session_id}
params=image_payload
)
except asyncio.TimeoutError:
_LOGGER.error("Timeout on %s", image_url)
except (asyncio.TimeoutError, aiohttp.errors.ClientError):
_LOGGER.exception("Error on %s", image_url)
return None

image = yield from response.read()
Expand All @@ -260,12 +264,12 @@ def handle_async_mjpeg_stream(self, request):
}
try:
with async_timeout.timeout(TIMEOUT, loop=self.hass.loop):
stream = yield from self.hass.websession.get(
stream = yield from self._websession.get(
streaming_url,
payload=streaming_payload,
cookies={'id': self._session_id}
params=streaming_payload
)
except asyncio.TimeoutError:
except (asyncio.TimeoutError, aiohttp.errors.ClientError):
_LOGGER.exception("Error on %s", streaming_url)
raise HTTPGatewayTimeout()

response = web.StreamResponse()
Expand Down
0