"""
Support for TP-Link routers.
For more details about this platform, please refer to the documentation at
[url]https://home-assistant.io/components/device_tracker.tplink/[/url]
"""
import base64
from datetime import datetime
import hashlib
import logging
import re
import json
from aiohttp.hdrs import (
ACCEPT, COOKIE, PRAGMA, REFERER, CONNECTION, KEEP_ALIVE, USER_AGENT,
CONTENT_TYPE, CACHE_CONTROL, ACCEPT_ENCODING, ACCEPT_LANGUAGE)
import requests
import voluptuous as vol
from homeassistant.components.device_tracker import (
DOMAIN, PLATFORM_SCHEMA, DeviceScanner)
from homeassistant.const import (
CONF_HOST, CONF_PASSWORD, CONF_USERNAME, HTTP_HEADER_X_REQUESTED_WITH)
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
HTTP_HEADER_NO_CACHE = 'no-cache'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Required(CONF_USERNAME): cv.string
})
def get_scanner(hass, config):
"""Validate the configuration and return a TP-Link scanner."""
scanner = TplinkDeviceScanner(config[DOMAIN])
if scanner.success_init:
return scanner
return None
class TplinkDeviceScanner(DeviceScanner):
"""This class queries the WDR6500 router."""
def __init__(self, config):
"""Initialize the scanner."""
host = config[CONF_HOST]
username, password = config[CONF_USERNAME], config[CONF_PASSWORD]
self.host = host
self.username = username
self.password = password
self.stok = ''
self.success_init = self._update_info()
def scan_devices(self):
"""Scan for new devices and return a list with found device IDs."""
self._update_info()
# self._log_out()
return self.last_results
# pylint: disable=no-self-use
def get_device_name(self, device):
"""Get the firmware doesn't save the name of the wireless device.
"""
return None
def _get_auth_tokens(self):
"""Retrieve auth tokens from the router."""
_LOGGER.info("Retrieving auth tokens...")
url_login = 'http://{}/'.format(self.host)
Y_passwd = '{}'.format(self.password)
En_passwd = Encrypt(passwd=Y_passwd).encrypt_passwd()
post_data = {'login': {'password': En_passwd}, 'method': 'do'}
get_Text = requests.post(url=url_login, json=post_data).text
get_data = json.loads(get_Text)
_LOGGER.info('login response:' + get_Text)
self.stok = get_data['stok']
_LOGGER.info(self.stok)
if (self.stok == ''):
return false
return True
def _update_info(self):
"""Ensure the information from the TP-Link router is up to date.
Return boolean if scanning successful.
"""
if (self.stok == ''):
self._get_auth_tokens()
result = []
_LOGGER.info("Loading wireless clients...")
online_host = {"hosts_info": {"table": "online_host"}, "method": "get"}
url_info = ('http://{}/stok={}/ds').format(self.host, self.stok)
host_json = requests.post(url=url_info, json=online_host).json()
try:
if host_json.get('error_code') == 0:
info = host_json['hosts_info']['online_host']
for i in list(range(len(info))):
result.append(list(info[i].values())[0]['mac'])
else:
if host_json.get('errorcode') == 'timeout':
_LOGGER.info("Token timed out. Relogging on next scan")
self.stok = ''
return False
_LOGGER.error(
"An unknown error happened while fetching data")
return False
except ValueError:
_LOGGER.error("Router didn't respond with JSON. Check if credentials are correct")
return False
if result:
# _LOGGER.info(result)
_LOGGER.info("Loading done.")
self.last_results = [mac.replace("-", ":") for mac in result]
return True
return False
def _log_out(self):
_LOGGER.info("Logging out of router admin interface...")
log_option = {"system": {"logout": "null"}, "method": "do"}
url_logout = ('http://{}/stok={}/ds').format(self.host, self.stok)
logOut_code = requests.post(url=url_logout, json=log_option).json()
if logOut_code['error_code'] == 0:
self.stok = ''
class Encrypt:
def __init__(self, passwd=None, flat=1):
self.passwd = passwd
self.Flat = flat
def encrypt_passwd(self):
a = "RDpbLfCPsJZ7fiv"
c = 'yLwVl0zKqws7LgKPRQ84Mdt708T1qQ3Ha7xv3H7NyU84p21BriUWBU43odz3iP4rBL3cD02KZciXTysVXiV8ngg6vL48rPJyAUw0HurW20xqxv9aYb4M9wK
1Ae0wlro510qXeU07kV57fQMc8L6aLgMLwygtc0F10a0Dg70TOoouyFhdysuRMO51yY5ZlOZZLEal1h0t9YQW0Ko7oBwmCAHoic4HYbUyVeU3sfQ1xtXcPcf1aT303wAQhv6
6qzW'
b = self.passwd
e = ''
f, g, h, k, l = 187, 187, 187, 187, 187
n = 187
g = len(a)
h = len(b)
k = len(c)
if g > h:
f = g
else:
f = h
for p in list(range(0, f)):
n = l = 187
if p >= g:
n = ord(b[p])
else:
if p >= h:
l = ord(a[p])
else:
l = ord(a[p])
n = ord(b[p])
e += c[(l ^ n) % k]
try:
if self.Flat == 0:
_LOGGER.info(e)
else:
return e
except NameError:
pass
2019-01-01 00:56:33 ERROR (MainThread) [homeassistant.components.device_tracker] Error setting up platform tplink6500
Traceback (most recent call last):
File "/usr/local/lib/python3.5/dist-packages/homeassistant/components/device_tracker/__init__.py", line 176, in async_setup_platform
platform.get_scanner, hass, {DOMAIN: p_config})
File "/usr/lib/python3.5/asyncio/futures.py", line 380, in __iter__
yield self # This tells Task to wait for completion.
File "/usr/lib/python3.5/asyncio/tasks.py", line 304, in _wakeup
future.result()
File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
raise self._exception
File "/usr/lib/python3.5/concurrent/futures/thread.py", line 55, in run
result = self.fn(*self.args, **self.kwargs)
File "/home/pi/.homeassistant/custom_components/device_tracker/tplink6500.py", line 39, in get_scanner
scanner = TplinkDeviceScanner(config[DOMAIN])
File "/home/pi/.homeassistant/custom_components/device_tracker/tplink6500.py", line 56, in __init__
self.success_init = self._update_info()
File "/home/pi/.homeassistant/custom_components/device_tracker/tplink6500.py", line 94, in _update_info
self._get_auth_tokens()
File "/home/pi/.homeassistant/custom_components/device_tracker/tplink6500.py", line 82, in _get_auth_tokens
self.stok = get_data['stok']
KeyError: 'stok'