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

 找回密码
 立即注册
查看: 10290|回复: 21

[插件集成] 适用于TL-R479GP-AC的device_tracker代码

[复制链接]

1

主题

7

帖子

129

积分

论坛技术达人

积分
129
金钱
122
HASS币
0
发表于 2017-12-29 09:37:47 | 显示全部楼层 |阅读模式
根据HomeAssistant官方tplink.py修改,请直接替换原有的tplink.py即可。按理来说TL-R473GP-AC等类似设备也可以使用。

"""
Support for TP-Link routers.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.tplink/
"""
import base64
from datetime import datetime
import hashlib
import logging
import re

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 TpDeviceScanner(DeviceScanner):
    """This class queries a wireless router running TP-Link firmware."""

    def __init__(self, config):
        """Initialize the scanner."""
        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.success_init = self._update_info()

    def scan_devices(self):
        """Scan for new devices and return a list with found device IDs."""
        self._update_info()
        return self.last_results

    # pylint: disable=no-self-use
    def get_device_name(self, device):
        """Get firmware doesn't save the name of the wireless device."""
        return None

    def _update_info(self):
        """Ensure the information from the TP-Link router is up to date.

        Return boolean if scanning successful.
        """
        _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}, timeout=4)

        result = self.parse_macs.findall(page.text)

        if result:
            self.last_results = [mac.replace("-", ":") for mac in result]
            return True

        return False

class TplinkDeviceScanner(TpDeviceScanner):
    """This class queries the Archer C9 router with version 150811 or high."""

    def __init__(self, config):
        """Initialize the scanner."""
        self.stok = ''
        self.sysauth = ''
        super(TplinkDeviceScanner, self).__init__(config)

    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.keys()

    # pylint: disable=no-self-use
    def get_device_name(self, device):
        """Get the firmware doesn't save the name of the wireless device.

        We are forced to use the MAC address as name here.
        """
        return self.last_results.get(device)

    def _get_auth_tokens(self):
        """Retrieve auth tokens from the router."""
        _LOGGER.info("Retrieving auth tokens...")


        url = 'http://{}/cgi-bin/luci/;stok=/login?form=login' \
            .format(self.host)
        referer = 'http://{}/webpages/login.html'.format(self.host)

        # If possible implement RSA encryption of password here.
        data = '{"method" : "login", "params": { "username": "' + self.username + '" , "password": "' + self.password + '"}}'
        response = requests.post(
            url, data={ 'data': data},
            headers={'Referer': referer})

        try:
            _LOGGER.info('1' + response.text)
            self.stok = response.json().get('result').get('stok')
            _LOGGER.info(self.stok)
            regex_result = re.search(
                'sysauth=(.*);', response.headers['set-cookie'])
            self.sysauth = regex_result.group(1)
            _LOGGER.info(self.sysauth)
            return True
        except (ValueError, KeyError) as _:
            _LOGGER.error("Couldn't fetch auth tokens! Response was: %s",
                          response.text)
            return False

    def _update_info(self):
        """Ensure the information from the TP-Link router is up to date.

        Return boolean if scanning successful.
        """
        if (self.stok == '') or (self.sysauth == ''):
            self._get_auth_tokens()

        _LOGGER.info("Loading wireless clients...")

        url = ('http://{}/cgi-bin/luci/;stok={}/admin/wlan_station?'
               'form=stainfo').format(self.host, self.stok)
        referer = 'http://{}/webpages/index.html'.format(self.host)

        data = '{"method" : "get", "params": { "key_idx": "-1"}}'
        response = requests.post(
            url, data={'data': data},headers={'Referer': referer},
            cookies={'sysauth': self.sysauth}, timeout=5)

        try:
            _LOGGER.error(response.text)
            json_response = response.json()

            if json_response.get('error_code') == '0':
                result = response.json().get('result').get('sta_info')
            else:
                if json_response.get('errorcode') == 'timeout':
                    _LOGGER.info("Token timed out. Relogging on next scan")
                    self.stok = ''
                    self.sysauth = ''
                    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:
            self.last_results = {
                device['sta_mac'].replace('-', ':'): device['host_name']
                for device in result
                }
            return True

        return False

    def _log_out(self):
        _LOGGER.info("Logging out of router admin interface...")

        url = ('http://{}/cgi-bin/luci/;stok={}/admin/system?'
               'form=logout').format(self.host, self.stok)
        referer = 'http://{}/webpages/index.html'.format(self.host)

        requests.post(
            url, params={'operation': 'write'}, headers={REFERER: referer},
            cookies={'sysauth': self.sysauth})
        self.stok = ''
        self.sysauth = ''

评分

参与人数 1金钱 +20 收起 理由
+ 20 膜拜大神!

查看全部评分

回复

使用道具 举报

123

主题

4626

帖子

1万

积分

管理员

囧死

Rank: 9Rank: 9Rank: 9

积分
16017
金钱
11306
HASS币
45
发表于 2017-12-29 09:55:39 | 显示全部楼层
牛了楼主,技术达人啊
回复

使用道具 举报

17

主题

418

帖子

2816

积分

金牌会员

Rank: 6Rank: 6

积分
2816
金钱
2398
HASS币
0

教程狂人

发表于 2017-12-29 10:25:49 | 显示全部楼层
Jones 发表于 2017-12-29 09:55
牛了楼主,技术达人啊

建议把论坛的连接识别默认禁用,我们论坛发的都是代码多,而且这个有用的都是发外链的时候,开了代码里面自动加[/url]非常坑

评分

参与人数 1金钱 +10 收起 理由
+ 10 已经修改了,试试?

查看全部评分

回复

使用道具 举报

13

主题

401

帖子

2745

积分

金牌会员

Rank: 6Rank: 6

积分
2745
金钱
2344
HASS币
0
发表于 2017-12-29 11:08:12 | 显示全部楼层
啥时候能支持华为荣耀路由器PRO?
回复

使用道具 举报

123

主题

4626

帖子

1万

积分

管理员

囧死

Rank: 9Rank: 9Rank: 9

积分
16017
金钱
11306
HASS币
45
发表于 2017-12-29 11:49:20 | 显示全部楼层
kay7758 发表于 2017-12-29 10:25
建议把论坛的连接识别默认禁用,我们论坛发的都是代码多,而且这个有用的都是发外链的时候,开了代码里面 ...

我试试,记得之前找过,没有这选项。再看看。
回复

使用道具 举报

123

主题

4626

帖子

1万

积分

管理员

囧死

Rank: 9Rank: 9Rank: 9

积分
16017
金钱
11306
HASS币
45
发表于 2017-12-29 11:59:41 | 显示全部楼层
http://test.com/bbb.html
回复

使用道具 举报

6

主题

388

帖子

2043

积分

金牌会员

Rank: 6Rank: 6

积分
2043
金钱
1655
HASS币
0
发表于 2017-12-30 00:30:41 | 显示全部楼层
咋没人弄个极路由的出来
回复

使用道具 举报

32

主题

986

帖子

4233

积分

论坛元老

Rank: 8Rank: 8

积分
4233
金钱
3207
HASS币
110

教程狂人论坛风云人物

发表于 2017-12-30 00:41:28 | 显示全部楼层
apple4105 发表于 2017-12-30 00:30
咋没人弄个极路由的出来

好建议!据说极路由固件是由开源系统深度定制的,实现起来应该不难。
回复

使用道具 举报

32

主题

986

帖子

4233

积分

论坛元老

Rank: 8Rank: 8

积分
4233
金钱
3207
HASS币
110

教程狂人论坛风云人物

发表于 2017-12-31 01:51:16 | 显示全部楼层
kay7758 发表于 2017-12-29 10:25
建议把论坛的连接识别默认禁用,我们论坛发的都是代码多,而且这个有用的都是发外链的时候,开了代码里面 ...

哎,这个建议真是让我欲哭无泪啊
回复

使用道具 举报

6

主题

388

帖子

2043

积分

金牌会员

Rank: 6Rank: 6

积分
2043
金钱
1655
HASS币
0
发表于 2017-12-31 02:12:42 | 显示全部楼层
27hh 发表于 2017-12-30 00:41
好建议!据说极路由固件是由开源系统深度定制的,实现起来应该不难。

对。。openwrt的。。。但是一直没人做啊

评分

参与人数 1金钱 +20 收起 理由
27hh + 20 早点休息~

查看全部评分

回复

使用道具 举报

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

本版积分规则

Archiver|手机版|小黑屋|Hassbian

GMT+8, 2024-5-2 13:04 , Processed in 0.060812 second(s), 34 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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