diff --git a/.gitignore b/.gitignore
index f92aa1b..6651715 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,10 @@
+*.pyc
+*.egg*
+.cache
+.coverage
+.idea
+.pytest_cache
+.tox
.vscode/
.DS_Store/
Test/
@@ -5,4 +12,3 @@ build/
dist/
pyubee.egg-info/
__pycache__
-
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 522353e..f773155 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,9 @@
# PyUbee CHANGELOG
This file is used to list changes made in each version of the PyUbee.
+## 0.4 (March 26 2019)
+* Detect Ubee model automatically ([@mzdrale](https://github.com/mzdrale) - [#5](https://github.com/mzdrale/pyubee/pull/5))
+
## 0.3 (March 12 2019)
* Add pyubee command line interface ([@StevenLooman](https://github.com/StevenLooman) - [#3](https://github.com/mzdrale/pyubee/pull/3))
* Add support for EVW3200-Wifi model ([@StevenLooman](https://github.com/StevenLooman) - [#3](https://github.com/mzdrale/pyubee/pull/3))
diff --git a/README.md b/README.md
index f5f54b9..4b2ee9c 100644
--- a/README.md
+++ b/README.md
@@ -16,8 +16,7 @@ from pyubee import Ubee
ubee = Ubee(
host='192.168.1.1',
username='admin',
- password='somepassword',
- model='EVW32C-0N'
+ password='somepassword'
)
if not ubee.session_active():
@@ -34,7 +33,7 @@ ubee.logout()
CLI
---
-A simple command line interface is available to query the router. The cli takes `host`, `username`, and `password` as mandatory arguments. The optional argument model can be used to specify the model of your routers (defaults to `EVW32C-0N`.)
+A simple command line interface is available to query the router. The cli takes `host`, `username`, and `password` as mandatory arguments. The optional argument model can be used to specify the model of your routers. If model is not specified, this tool will try to detect it automatically.
```
$ pyubee --help
usage: pyubee [-h] [--model MODEL] host username password
@@ -50,9 +49,9 @@ optional arguments:
-h, --help show this help message and exit
--model MODEL Model, supported models: EVW32C-0N, EVW3200-Wifi
-$ pyubee 192.168.1.1 admin somepassword --model EVW3200-Wifi
-AA:BB:CC:DD:EE:FF 192.168.001.010
-FF:EE:DD:CC:BB:AA 192.168.001.011
+$ pyubee 192.168.1.1 admin somepassword
+AA:BB:CC:DD:EE:FF 192.168.1.10
+FF:EE:DD:CC:BB:AA 192.168.1.11
```
Notice
@@ -96,3 +95,4 @@ This library was written for and tested with:
* Ubee EVW32C-0N
* Ubee EVW3200-Wifi
+* Ambit EVW320B
diff --git a/pyubee/__init__.py b/pyubee/__init__.py
index 5f82ede..1e6a651 100644
--- a/pyubee/__init__.py
+++ b/pyubee/__init__.py
@@ -2,7 +2,6 @@
import logging
import re
-import sys
import requests
from requests.exceptions import RequestException
@@ -10,6 +9,8 @@
_LOGGER = logging.getLogger(__name__)
+MODEL_REGEX = re.compile(r'(.*)')
+
MODELS = {
'EVW32C-0N': {
'url_session_active': '/UbeeSysInfo.asp',
@@ -20,7 +21,7 @@
'regex_login': re.compile(r'
Residential Gateway Login'),
'regex_wifi_devices': re.compile(
r''
- r'([0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:' # mac address
+ r' | ([0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:' # mac address
r'[0-9a-fA-F]{2}:[0-9a-fA-F]{2}) | ' # mac address, cont'd
r'\d+ | ' # age
r'.+ | ' # rssi
@@ -37,7 +38,7 @@
r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) | ' # ip address
),
},
- 'EVW3200-Wifi': {
+ 'EVW320B': {
'url_session_active': '/BasicStatus.asp',
'url_login': '/goform/loginMR3',
'url_logout': '/logout.asp',
@@ -46,7 +47,7 @@
'regex_login': re.compile(r'Residential Gateway Login'),
'regex_wifi_devices': re.compile(
r'
'
- r'([0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:' # mac address
+ r' | ([0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:' # mac address
r'[0-9a-fA-F]{2}:[0-9a-fA-F]{2}) | ' # mac address, cont'd
r'\d+ | ' # age
r'.+ | ' # rssi
@@ -70,27 +71,58 @@
class Ubee:
"""Represents a session to a Ubee Router."""
- def __init__(self, host=None, username=None, password=None, model='EVW32C-0N'):
+ def __init__(self, host=None, username=None, password=None, model='detect'):
"""Initialize a Ubee session."""
+ self.host = host
+ self.username = username
+ self.password = password
+
+ if model == 'detect':
+ model = self.detect_model()
if model not in MODELS:
raise LookupError('Unknown model')
- self.host = host
- self.username = username
- self.password = password
self.model = model
self._model_info = MODELS[model]
@property
def _base_url(self):
+ """Form base url."""
return 'http://{}'.format(self.host)
+ def _get(self, url):
+ """Do a HTTP GET."""
+ # pylint: disable=no-self-use
+ return requests.get(url, timeout=4)
+
+ def _post(self, url, data):
+ """Do a HTTP POST."""
+ # pylint: disable=no-self-use
+ return requests.post(url, data=data, timeout=4)
+
+ def detect_model(self):
+ """Autodetect Ubee model."""
+ url = self._base_url + "/RootDevice.xml"
+ try:
+ response = self._get(url)
+ except RequestException as ex:
+ _LOGGER.error("Connection to the router failed: %s", ex)
+ return "Unknown"
+
+ data = response.text
+ entries = MODEL_REGEX.findall(data)
+
+ if entries:
+ return entries[1]
+
+ return "Unknown"
+
def session_active(self):
"""Check if session is active."""
url = self._base_url + self._model_info['url_session_active']
try:
- response = requests.get(url, timeout=4)
+ response = self._get(url)
except RequestException as ex:
_LOGGER.error("Connection to the router failed: %s", ex)
return False
@@ -110,7 +142,7 @@ def login(self):
'loginPassword': self.password
}
try:
- response = requests.post(url, data=payload, timeout=4)
+ response = self._post(url, payload)
except RequestException as ex:
_LOGGER.error("Connection to the router failed: %s", ex)
return False
@@ -127,10 +159,10 @@ def login(self):
return False
def logout(self):
- """Logout from Admin interface"""
+ """Logout from Admin interface."""
url = self._base_url + self._model_info['url_logout']
try:
- response = requests.get(url, timeout=4)
+ response = self._get(url)
except RequestException as ex:
_LOGGER.error("Connection to the router failed: %s", ex)
return False
@@ -141,7 +173,7 @@ def logout(self):
return False
def get_connected_devices(self):
- """Get list of connected devices"""
+ """Get list of connected devices."""
lan_devices = self.get_connected_devices_lan()
_LOGGER.debug('LAN devices: %s', lan_devices)
wifi_devices = self.get_connected_devices_wifi()
@@ -150,17 +182,11 @@ def get_connected_devices(self):
devices.update(wifi_devices)
return devices
- def _format_mac_address(self, address):
- """Format a given address to a default format."""
- # remove all ':' and '-'
- bare = address.upper().replace(':', '').replace('-', '')
- return ':'.join(bare[i:i + 2] for i in range(0, 12, 2))
-
def get_connected_devices_lan(self):
"""Get list of connected devices via ethernet."""
url = self._base_url + self._model_info['url_connected_devices_lan']
try:
- response = requests.get(url, timeout=4)
+ response = self._get(url)
except RequestException as ex:
_LOGGER.error("Connection to the router failed: %s", ex)
return []
@@ -176,7 +202,7 @@ def get_connected_devices_wifi(self):
"""Get list of connected devices via wifi."""
url = self._base_url + self._model_info['url_connected_devices_wifi']
try:
- response = requests.get(url, timeout=4)
+ response = self._get(url)
except RequestException as ex:
_LOGGER.error("Connection to the router failed: %s", ex)
return []
@@ -187,3 +213,10 @@ def get_connected_devices_wifi(self):
self._format_mac_address(address): hostname
for address, hostname in entries
}
+
+ def _format_mac_address(self, address):
+ """Format a given address to a default format."""
+ # pylint: disable=no-self-use
+ # remove all ':' and '-'
+ bare = address.upper().replace(':', '').replace('-', '')
+ return ':'.join(bare[i:i + 2] for i in range(0, 12, 2))
diff --git a/pyubee/__main__.py b/pyubee/__main__.py
index 3061a4f..cbe52a0 100644
--- a/pyubee/__main__.py
+++ b/pyubee/__main__.py
@@ -12,7 +12,7 @@ def main():
parser.add_argument('host', help='Host')
parser.add_argument('username', help='Username')
parser.add_argument('password', help='Password')
- parser.add_argument('--model', default="EVW32C-0N",
+ parser.add_argument('-m', '--model', default="detect",
help='Model, supported models: ' + ', '.join(SUPPORTED_MODELS))
args = parser.parse_args()
@@ -27,8 +27,13 @@ def main():
sys.exit(1)
devices = ubee.get_connected_devices()
- for device in devices:
- print("%s\t%s" % (device, devices[device]))
+
+ if devices:
+ print("Connected devices:")
+ for device in devices:
+ print("%s\t%s" % (device, devices[device]))
+ else:
+ print("No connected devices found")
if __name__ == '__main__':
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..73137bf
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,5 @@
+[metadata]
+license_file = LICENSE
+
+[flake8]
+max-line-length = 119
diff --git a/setup.py b/setup.py
index 56249d0..b7c8c6f 100644
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@
setuptools.setup(
name="pyubee",
- version="0.3",
+ version="0.4.dev2",
author="Miroslav Zdrale",
author_email="mzdrale@gmail.com",
description="Simple library for getting stats from Ubee routers.",
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..a076f60
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,22 @@
+[tox]
+envlist = py35, py36, py37, flake8, pylint, pydocstyle
+
+[testenv:flake8]
+basepython = python3
+ignore_errors = True
+deps = flake8
+commands = flake8 pyubee
+
+[testenv:pylint]
+basepython = python3
+ignore_errors = True
+deps =
+ pylint
+ requests
+commands = pylint pyubee
+
+[testenv:pydocstyle]
+basepython = python3
+ignore_errors = True
+deps = pydocstyle
+commands = pydocstyle pyubee