From ac73c4db0f7f39fedaa9183f8e4cb131780fa761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Arnauts?= Date: Wed, 17 Jun 2015 22:55:03 +0200 Subject: [PATCH 1/4] Add TP-Link support for device_tracker --- .../components/device_tracker/tplink.py | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100755 homeassistant/components/device_tracker/tplink.py diff --git a/homeassistant/components/device_tracker/tplink.py b/homeassistant/components/device_tracker/tplink.py new file mode 100755 index 00000000000..61771e718a7 --- /dev/null +++ b/homeassistant/components/device_tracker/tplink.py @@ -0,0 +1,117 @@ +""" +homeassistant.components.device_tracker.tplink +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Device tracker platform that supports scanning a TP-Link router for device +presence. + +Configuration: + +To use the TP-Link tracker you will need to add something like the following +to your config/configuration.yaml + +device_tracker: + platform: tplink + host: YOUR_ROUTER_IP + username: YOUR_ADMIN_USERNAME + password: YOUR_ADMIN_PASSWORD + +Variables: + +host +*Required +The IP address of your router, e.g. 192.168.1.1. + +username +*Required +The username of an user with administrative privileges, usually 'admin'. + +password +*Required +The password for your given admin account. + +""" +import logging +from datetime import timedelta +import re +import threading +import requests + +from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD +from homeassistant.helpers import validate_config +from homeassistant.util import Throttle +from homeassistant.components.device_tracker import DOMAIN + +# Return cached results if last scan was less then this time ago +MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) + +_LOGGER = logging.getLogger(__name__) + + +def get_scanner(hass, config): + """ Validates config and returns a TP-Link scanner. """ + if not validate_config(config, + {DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]}, + _LOGGER): + return None + + scanner = TplinkDeviceScanner(config[DOMAIN]) + + return scanner if scanner.success_init else None + + +class TplinkDeviceScanner(object): + """ This class queries a wireless router running TP-Link firmware + for connected devices. + """ + + def __init__(self, config): + host = config[CONF_HOST] + username, password = config[CONF_USERNAME], config[CONF_PASSWORD] + + self.parse_macs = re.compile('[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}') + + self.host = host + self.username = username + self.password = password + + self.last_results = {} + self.lock = threading.Lock() + self.success_init = self._update_info() + + def scan_devices(self): + """ Scans for new devices and return a + list containing found device ids. """ + + self._update_info() + + return self.last_results + + def get_device_name(self, device): + """ The TP-Link firmware doesn't save the name of the wireless + device. """ + + return None + + @Throttle(MIN_TIME_BETWEEN_SCANS) + def _update_info(self): + """ Ensures the information from the TP-Link router is up to date. + Returns boolean if scanning successful. """ + + with self.lock: + _LOGGER.info("Loading wireless clients...") + + url = 'http://{}/userRpm/WlanStationRpm.htm'.format(self.host) + referer = 'http://{}'.format(self.host) + page = requests.get(url, auth=(self.username, self.password), headers={'referer': referer}) + + result = self.parse_macs.findall(page.text) + + if result: + self.last_results = [] + for device_entry in result: + self.last_results.append(device_entry) + + return True + + return False From c77dbaa67b3222a6444af5137206bc425b0976ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Arnauts?= Date: Wed, 17 Jun 2015 23:32:33 +0200 Subject: [PATCH 2/4] Fix code guidelines --- homeassistant/components/device_tracker/tplink.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/device_tracker/tplink.py b/homeassistant/components/device_tracker/tplink.py index 61771e718a7..49d31a2aefd 100755 --- a/homeassistant/components/device_tracker/tplink.py +++ b/homeassistant/components/device_tracker/tplink.py @@ -69,7 +69,8 @@ class TplinkDeviceScanner(object): host = config[CONF_HOST] username, password = config[CONF_USERNAME], config[CONF_PASSWORD] - self.parse_macs = re.compile('[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}') + self.parse_macs = re.compile('[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-'+ + '[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}') self.host = host self.username = username @@ -89,7 +90,7 @@ class TplinkDeviceScanner(object): def get_device_name(self, device): """ The TP-Link firmware doesn't save the name of the wireless - device. """ + device. """ return None @@ -103,10 +104,11 @@ class TplinkDeviceScanner(object): url = 'http://{}/userRpm/WlanStationRpm.htm'.format(self.host) referer = 'http://{}'.format(self.host) - page = requests.get(url, auth=(self.username, self.password), headers={'referer': referer}) - + page = requests.get(url, auth=(self.username, self.password), + headers={'referer': referer}) + result = self.parse_macs.findall(page.text) - + if result: self.last_results = [] for device_entry in result: From e5147235cc77556baa946ad9452f8d6a6b8270cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Arnauts?= Date: Wed, 17 Jun 2015 23:40:58 +0200 Subject: [PATCH 3/4] More code style fixes --- homeassistant/components/device_tracker/tplink.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/device_tracker/tplink.py b/homeassistant/components/device_tracker/tplink.py index 49d31a2aefd..9bc756d745a 100755 --- a/homeassistant/components/device_tracker/tplink.py +++ b/homeassistant/components/device_tracker/tplink.py @@ -69,7 +69,7 @@ class TplinkDeviceScanner(object): host = config[CONF_HOST] username, password = config[CONF_USERNAME], config[CONF_PASSWORD] - self.parse_macs = re.compile('[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-'+ + self.parse_macs = re.compile('[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-' + '[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}') self.host = host @@ -89,7 +89,7 @@ class TplinkDeviceScanner(object): return self.last_results def get_device_name(self, device): - """ The TP-Link firmware doesn't save the name of the wireless + """ The TP-Link firmware doesn't save the name of the wireless device. """ return None From abea8a2ff4700b6017e1c9b78987d5b5aa304170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Arnauts?= Date: Fri, 19 Jun 2015 20:58:01 +0200 Subject: [PATCH 4/4] disable pylint warning, use correct format for mac addresses --- homeassistant/components/device_tracker/tplink.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/device_tracker/tplink.py b/homeassistant/components/device_tracker/tplink.py index 9bc756d745a..24d170a5de7 100755 --- a/homeassistant/components/device_tracker/tplink.py +++ b/homeassistant/components/device_tracker/tplink.py @@ -88,6 +88,7 @@ class TplinkDeviceScanner(object): return self.last_results + # pylint: disable=no-self-use def get_device_name(self, device): """ The TP-Link firmware doesn't save the name of the wireless device. """ @@ -110,10 +111,7 @@ class TplinkDeviceScanner(object): result = self.parse_macs.findall(page.text) if result: - self.last_results = [] - for device_entry in result: - self.last_results.append(device_entry) - + self.last_results = [mac.replace("-", ":") for mac in result] return True return False