Skip to content

Commit

Permalink
Merge pull request #109 from tchellomello/1.2.6
Browse files Browse the repository at this point in the history
1.2.6
  • Loading branch information
pnbruckner authored Mar 13, 2019
2 parents e8a3a88 + 4668996 commit fbf9811
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 58 deletions.
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# GNU General Public License for more details.
define([VERSION_MAJOR], [1])
define([VERSION_MINOR], [2])
define([VERSION_FIX], [5])
define([VERSION_FIX], [6])
define([VERSION_NUMBER], VERSION_MAJOR[.]VERSION_MINOR[.]VERSION_FIX)
define([VERSION_SUFFIX], [_master])

Expand Down
3 changes: 2 additions & 1 deletion pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ disable=
too-many-statements,
too-many-lines,
too-few-public-methods,
abstract-method
abstract-method,
useless-object-inheritance

[EXCEPTIONS]
overgeneral-exceptions=Exception
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def readme():


setup(name='amcrest',
version='1.2.5',
version='1.2.6',
description='Python wrapper implementation for Amcrest cameras.',
long_description=readme(),
author='Douglas Schilling Landgraf, Marcelo Moreira de Mello',
Expand Down
4 changes: 2 additions & 2 deletions src/amcrest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
# GNU General Public License for more details.
#
# vim:sw=4:ts=4:et

from amcrest.http import Http
from .exceptions import AmcrestError, CommError, LoginError # noqa: F401
from .http import Http


class AmcrestCamera(object):
Expand Down
17 changes: 17 additions & 0 deletions src/amcrest/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""
amcrest.exceptions
This module contains the set of amcrest's exceptions.
"""


class AmcrestError(Exception):
"""General Amcrest error occurred."""


class CommError(AmcrestError):
"""A communication error occurred."""


class LoginError(AmcrestError):
"""A login error occurred."""
99 changes: 51 additions & 48 deletions src/amcrest/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,29 @@
#
# vim:sw=4:ts=4:et
import logging

import requests
from requests.adapters import HTTPAdapter

from amcrest.utils import clean_url, pretty

from amcrest.audio import Audio
from amcrest.event import Event
from amcrest.log import Log
from amcrest.motion_detection import MotionDetection
from amcrest.nas import Nas
from amcrest.network import Network
from amcrest.ptz import Ptz
from amcrest.record import Record
from amcrest.snapshot import Snapshot
from amcrest.special import Special
from amcrest.storage import Storage
from amcrest.system import System
from amcrest.user_management import UserManagement
from amcrest.video import Video

from amcrest.config import TIMEOUT_HTTP_PROTOCOL, MAX_RETRY_HTTP_CONNECTION
from .exceptions import CommError, LoginError
from .utils import clean_url, pretty

from .audio import Audio
from .event import Event
from .log import Log
from .motion_detection import MotionDetection
from .nas import Nas
from .network import Network
from .ptz import Ptz
from .record import Record
from .snapshot import Snapshot
from .special import Special
from .storage import Storage
from .system import System
from .user_management import UserManagement
from .video import Video

from .config import TIMEOUT_HTTP_PROTOCOL, MAX_RETRY_HTTP_CONNECTION

_LOGGER = logging.getLogger(__name__)

Expand All @@ -53,39 +55,47 @@ def __init__(self, host, port, user,
self._protocol = protocol
self._base_url = self.__base_url()

self._retries_default = (retries_connection or
MAX_RETRY_HTTP_CONNECTION)
self._retries_default = (
retries_connection or MAX_RETRY_HTTP_CONNECTION)
self._timeout_default = timeout_protocol or TIMEOUT_HTTP_PROTOCOL

self._token = self._generate_token()
self._set_name()

def _generate_token(self):
"""Discover which authentication method to use.
def get_session(self, max_retries=None):
session = requests.Session()
max_retries = max_retries or self._retries_default
adapter = HTTPAdapter(max_retries=max_retries)
session.mount('http://', adapter)
session.mount('https://', adapter)
return session

Latest firmwares requires HttpDigestAuth
Older firmwares requires HttpBasicAuth
"""
def _generate_token(self):
"""Create authentation to use with requests."""
session = self.get_session()
url = self.__base_url('magicBox.cgi?action=getMachineName')
try:
# try old firmware first to force 401 if fails
self._authentication = 'basic'
# try old basic method
auth = requests.auth.HTTPBasicAuth(self._user, self._password)
req = requests.get(url, auth=auth)
req = session.get(url, auth=auth, timeout=self._timeout_default)
if not req.ok:
# try new digest method
auth = requests.auth.HTTPDigestAuth(
self._user, self._password)
req = session.get(
url, auth=auth, timeout=self._timeout_default)
req.raise_for_status()
except requests.RequestException as error:
_LOGGER.error(error)
raise CommError('Could not communicate with camera')

except requests.HTTPError:
# if 401, then try new digest method
self._authentication = 'digest'
auth = requests.auth.HTTPDigestAuth(self._user, self._password)
req = requests.get(url, auth=auth)
req.raise_for_status()
# check if user passed
result = req.text.lower()
if 'invalid' in result or 'error' in result:
_LOGGER.error('Result from camera: %s',
req.text.strip().replace('\r\n', ': '))
raise LoginError('Invalid credentials')

# check if user passed
if 'invalid' in req.text.lower() or \
'error' in req.text.lower():
_LOGGER.info("%s Invalid credentials", req.text)
raise
return auth

def _set_name(self):
Expand Down Expand Up @@ -117,13 +127,6 @@ def __base_url(self, param=""):
def get_base_url(self):
return self._base_url

def get_session(self, max_retries):
session = requests.Session()
adapter = HTTPAdapter(max_retries=max_retries)
session.mount('http://', adapter)
session.mount('https://', adapter)
return session

def command(self, cmd, retries=None, timeout_cmd=None):
"""
Args:
Expand All @@ -147,13 +150,13 @@ def command(self, cmd, retries=None, timeout_cmd=None):
)
resp.raise_for_status()
break
except requests.HTTPError as error:
except requests.RequestException as error:
if loop <= retries:
_LOGGER.warning("Trying again due to error %s", error)
continue
else:
_LOGGER.error("Query failed due to error %s", error)
raise
raise CommError('Could not communicate with camera')

_LOGGER.debug("Query worked. Exit code: <%s>", resp.status_code)
return resp
Expand Down
7 changes: 2 additions & 5 deletions tui/amcrest-tui
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,8 @@ if __name__ == "__main__":
args = parser.parse_args()

# Check if we have permission to framebuffer device
try:
with open(args.framebuffer_device, 'r') as f:
pass
except Exception:
raise
with open(args.framebuffer_device, 'r') as f:
pass

# pylint: disable=fixme
# FIXME: Add option to save the snapshots in the disk
Expand Down

0 comments on commit fbf9811

Please sign in to comment.