Skip to content
This repository has been archived by the owner on Aug 16, 2024. It is now read-only.

Commit

Permalink
Merge pull request #48 from cpainchaud/main
Browse files Browse the repository at this point in the history
support for HTTPS based API
  • Loading branch information
cpainchaud authored Oct 8, 2021
2 parents b210518 + 1274e6d commit 0ea20bb
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 12 deletions.
33 changes: 25 additions & 8 deletions reolink/camera_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import urllib.parse as parse

MANUFACTURER = "Reolink"
DEFAULT_USE_SSL = False
DEFAULT_STREAM = "main"
DEFAULT_PROTOCOL = "rtmp"
DEFAULT_CHANNEL = 0
Expand All @@ -26,6 +27,7 @@


ref_sw_version_3_0_0_0_0 = SoftwareVersion("v3.0.0.0_0")
ref_sw_version_3_1_0_0_0 = SoftwareVersion("v3.1.0.0_0")


class Api: # pylint: disable=too-many-instance-attributes disable=too-many-public-methods
Expand All @@ -37,6 +39,7 @@ def __init__(
port,
username,
password,
use_https=DEFAULT_USE_SSL,
channel=DEFAULT_CHANNEL,
protocol=DEFAULT_PROTOCOL,
stream=DEFAULT_STREAM,
Expand All @@ -45,7 +48,7 @@ def __init__(
rtmp_auth_method=DEFAULT_RTMP_AUTH_METHOD,
):
"""Initialize the API class."""
self._url = f"http://{host}:{port}/cgi-bin/api.cgi"
self._url = ""
self._host = host
self._port = port
self._username = username
Expand All @@ -56,6 +59,7 @@ def __init__(
self._stream_format = stream_format
self._rtmp_auth_method = rtmp_auth_method
self._timeout = aiohttp.ClientTimeout(total=timeout)
self._use_https = use_https

self._token = None
self._lease_time = None
Expand Down Expand Up @@ -103,6 +107,18 @@ def __init__(

self._is_nvr = False

self.refresh_base_url()

def enable_https(self, enable: bool):
self._use_https = enable
self.refresh_base_url()

def refresh_base_url(self):
if self._use_https:
self._url = f"https://{self._host}:{self._port}/cgi-bin/api.cgi"
else:
self._url = f"http://{self._host}:{self._port}/cgi-bin/api.cgi"

@property
def host(self):
"""Return the host."""
Expand Down Expand Up @@ -339,7 +355,7 @@ async def get_states(self, cmd_list=None):
{"cmd": "GetPushV20", "action": 1, "param": {"channel": self._channel}},
]

if not self._is_nvr:
if not self._is_nvr and self._sw_version_object < ref_sw_version_3_1_0_0_0:
# NVR would crash without this
body.append({"cmd": "GetPush", "action": 1, "param": {"channel": self._channel}})

Expand Down Expand Up @@ -971,7 +987,6 @@ async def send_search(

try:
json_data = json.loads(response)
_LOGGER.debug("Response from %s: %s", self._host, json_data)
except (TypeError, json.JSONDecodeError):
_LOGGER.debug(
"Host %s: Error translating %s response to json", self._host, command
Expand All @@ -994,7 +1009,7 @@ async def send_search(

return search_result["Status"], search_result["File"]

_LOGGER.debug("Host: %s: Failed to get results for %s", self._host, command)
_LOGGER.warning("Host: %s: Failed to get results for %s, JSON data was was empty?", self._host, command)
return None, None

async def send_setting(self, body):
Expand Down Expand Up @@ -1046,8 +1061,9 @@ async def send(self, body, param=None):

try:
if body is None:
async with aiohttp.ClientSession(timeout=self._timeout) as session:
async with session.get(url=self._url, params=param) as response:
async with aiohttp.ClientSession(timeout=self._timeout,
connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
async with session.get(url=self._url, params=param, allow_redirects=False) as response:
_LOGGER.debug("send()= HTTP Request params =%s", str(param).replace(self._password, "<password>"))
json_data = await response.read()
_LOGGER.debug("send HTTP Response status=%s", str(response.status))
Expand All @@ -1058,9 +1074,10 @@ async def send(self, body, param=None):

return json_data
else:
async with aiohttp.ClientSession(timeout=self._timeout) as session:
async with aiohttp.ClientSession(timeout=self._timeout,
connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
async with session.post(
url=self._url, json=body, params=param
url=self._url, json=body, params=param, allow_redirects=False
) as response:
_LOGGER.debug("send() HTTP Request params =%s", str(param).replace(self._password, "<password>"))
_LOGGER.debug("send() HTTP Request body =%s", str(body).replace(self._password, "<password>"))
Expand Down
14 changes: 11 additions & 3 deletions reolink/subscription_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,18 +81,26 @@ async def send(self, headers, data):
"""Send data to the camera."""

try:
async with aiohttp.ClientSession(timeout=self._timeout) as session:
async with aiohttp.ClientSession(timeout=self._timeout,
connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
_LOGGER.debug(
"Reolink host %s (Subscription) request data: %s",
self._host, data
)

async with session.post(
url=self._subscribe_url, data=data, headers=headers
url=self._subscribe_url, data=data, headers=headers, allow_redirects=False
) as response:
response_xml = await response.text()

_LOGGER.debug(
"Reolink host %s got response status: %s. Payload: {%s}",
"Reolink host %s (Subscription) got response status: %s. Payload: %s",
self._host, response.status, response_xml
)
if response.status == 200:
return response_xml
else:
_LOGGER.warning("Subscription process ended with wrong HTTP status: %s: %s", response.status, response.reason)

return

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
setup(
name='reolink',
packages=['reolink'],
version='0.0.26',
version='0.0.27',
license='MIT',
description='Reolink camera package',
author='fwestenberg',
Expand Down

0 comments on commit 0ea20bb

Please sign in to comment.