2015-06-17 20:55:03 +00:00
|
|
|
"""
|
|
|
|
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]
|
|
|
|
|
2015-06-17 21:40:58 +00:00
|
|
|
self.parse_macs = re.compile('[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-' +
|
2015-06-17 21:32:33 +00:00
|
|
|
'[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}')
|
2015-06-17 20:55:03 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2015-06-19 18:58:01 +00:00
|
|
|
# pylint: disable=no-self-use
|
2015-06-17 20:55:03 +00:00
|
|
|
def get_device_name(self, device):
|
2015-06-17 21:40:58 +00:00
|
|
|
""" The TP-Link firmware doesn't save the name of the wireless
|
2015-06-17 21:32:33 +00:00
|
|
|
device. """
|
2015-06-17 20:55:03 +00:00
|
|
|
|
|
|
|
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)
|
2015-06-17 21:32:33 +00:00
|
|
|
page = requests.get(url, auth=(self.username, self.password),
|
|
|
|
headers={'referer': referer})
|
|
|
|
|
2015-06-17 20:55:03 +00:00
|
|
|
result = self.parse_macs.findall(page.text)
|
2015-06-17 21:32:33 +00:00
|
|
|
|
2015-06-17 20:55:03 +00:00
|
|
|
if result:
|
2015-06-19 18:58:01 +00:00
|
|
|
self.last_results = [mac.replace("-", ":") for mac in result]
|
2015-06-17 20:55:03 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|