『瀚思彼岸』» 智能家居技术论坛

 找回密码
 立即注册
查看: 9948|回复: 11

[插件集成] 针对TP-link WDR6500的插件

[复制链接]

4

主题

85

帖子

487

积分

论坛技术达人

积分
487
金钱
397
HASS币
0
发表于 2018-9-2 20:20:32 | 显示全部楼层 |阅读模式
    各种device_tracker插件对我的TP-link WDR6500都无用,一直想自己写一个,这个周末终于行动了。简单了解了一下插件原理,一边摸索一边测试。由于第一次用python,各种不熟悉各种坑啊,代码缩进简直把我搞醉了,重启了无数次hassio来验证代码正确性。
    翻6500登陆界面源码的时候发现了class.js,然后从这个JS中找到密码加密的函数,最后把它集成到了插件中。所以我们在配置configuration.yaml的时候,可以填写明文密码了,不用再自己去找加密后的字符串。同时,用户名也可以不用配置,登陆时不需要用户名。Post数据主要是用chrome分析得来的,这个很重要。
    WDR6500,WR886N这些登陆密码用同样加密方式路由器应该都能用,其它的没有测试。希望对用这些TP-link路由器的同学有所帮助。
"""
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



配置文件:
device_tracker:
  - platform: tplink6500
    host: 192.168.2.1
#    username: admin
    password: xxxxx 
    interval_seconds: 10 # scan every 10 seconds
    consider_home: 180
    track_new_devices: yes


评分

参与人数 4金钱 +44 收起 理由
trz0332 + 10 论坛有你更精彩!
windgo + 10 膜拜大神!
jyz_0501 + 4 膜拜大神!
+ 20 在下对你的景仰犹如滔滔长江之水,连绵不绝.

查看全部评分

回复

使用道具 举报

7

主题

1977

帖子

5671

积分

论坛元老

流水无味

Rank: 8Rank: 8

积分
5671
金钱
3694
HASS币
145

灌水之王

发表于 2018-9-2 20:47:54 | 显示全部楼层
我的6500当纯ap了
回复

使用道具 举报

4

主题

85

帖子

487

积分

论坛技术达人

积分
487
金钱
397
HASS币
0
 楼主| 发表于 2018-9-2 21:07:45 | 显示全部楼层
我一个k2p一个6500,之前k2p刷了官改最新固件,结果wifi不稳定,时有时无,就刷回了官方固件。现在变成k2p做AP,6500当主路由了。是不是有点本末倒置不想折腾了。
回复

使用道具 举报

123

主题

4630

帖子

1万

积分

管理员

囧死

Rank: 9Rank: 9Rank: 9

积分
16083
金钱
11368
HASS币
45
发表于 2018-9-2 21:49:14 | 显示全部楼层
楼主你搞大了,现学python写插件啊,膜拜!
回复

使用道具 举报

30

主题

999

帖子

4119

积分

论坛元老

Rank: 8Rank: 8

积分
4119
金钱
3115
HASS币
0

活跃会员

发表于 2018-9-3 08:24:12 | 显示全部楼层
感谢大神,希望我的WDR6600能通用
回复

使用道具 举报

30

主题

999

帖子

4119

积分

论坛元老

Rank: 8Rank: 8

积分
4119
金钱
3115
HASS币
0

活跃会员

发表于 2018-9-3 12:06:42 | 显示全部楼层
确认WDR6600能通用,再次感谢!!
回复

使用道具 举报

0

主题

163

帖子

1017

积分

金牌会员

Rank: 6Rank: 6

积分
1017
金钱
854
HASS币
0
发表于 2018-11-29 12:18:35 | 显示全部楼层
TL-WR882N3.0测试成功,流程是把楼主的代码另存为tplink6500.py放到/homeassistant/custom_components/device_tracker目录下,并修改第143-144行,合并到142行,不然会报错
回复

使用道具 举报

0

主题

4

帖子

27

积分

新手上路

Rank: 1

积分
27
金钱
23
HASS币
0
发表于 2019-1-1 01:45:55 | 显示全部楼层
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'


这个是错误日志,我的路由器是6300,,题主可以看下嘛
回复

使用道具 举报

1

主题

32

帖子

174

积分

论坛DIY达人

积分
174
金钱
142
HASS币
20
发表于 2019-4-29 16:21:39 | 显示全部楼层
顶一下,准备自己写一个LT-AC100的插件
回复

使用道具 举报

46

主题

641

帖子

4398

积分

元老级技术达人

积分
4398
金钱
3727
HASS币
120
发表于 2019-8-24 21:23:43 | 显示全部楼层
hassio 0.96.2 设备TL-WDR6300,测试成功,感谢楼主分享。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Hassbian

GMT+8, 2024-5-15 13:02 , Processed in 0.269236 second(s), 39 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表