sakowicz / home-assistant-tenda-tracker

Track your devices via Tenda AC23 router using Home Assistant's device tracker
6 stars 4 forks source link

/goform/GetIpMacBind #2

Open cs301cs301 opened 11 months ago

cs301cs301 commented 11 months ago

Hi, i have the Tenda TX3 router. The plugin also works on this router. However, the goform page is not the right one. The /goform/getOnlineList shows all devices that are known to the router, so all devices are online. The devices that are online are displayed on the goform/GetIpMacBind page. There is an entry "status", which is 0 or 1. I have tried to adapt the script to this, but I fail. All devices are displayed as offline. Could you change the script to this page?

{"lanIp":"192.168.1.35","lanMask":"255.255.255.0","dhttpIP":"0.0.0.0","dhcpClientList":[{"ipaddr":"192.168.1.217","macaddr":"02:xxxxx:97","devname":"homeassistant","status":"1"}, {"ipaddr":"192.168.1.225","macaddr":"14:xxxxx:26","devname":"CoreELEC","status":"1"}, {"ipaddr":"192.168.1.125","macaddr":"30:xxxxx:e1","devname":"HF-LPB130","status":"1"}, {"ipaddr":"192.168.1.139","macaddr":"98:xxxxx:ae","devname":"HF-LPB130","status":"1"}],"bindList":[{"ipaddr":"192.168.1.252","macaddr":"b8:xxxxxxx:60","devname":"klipper","status":"1"}, {"ipaddr":"192.168.1.200","macaddr":"60:xxxxxxx:5c","devname":"Licht","status":"1"}, {"ipaddr":"192.168.1.201","macaddr":"3c:xxxxxx:76","devname":"Lampe","status":"1"}, {"ipaddr":"192.168.1.202","macaddr":"70:xxxxxxx:b9","devname":"Steckdose","status":"1"}, {"ipaddr":"192.168.1.165","macaddr":"bc:xxxxxxx:8d","devname":"Mi9TPro","status":"1"}, {"ipaddr":"192.168.1.142","macaddr":"08:xxxxxxx:6c","devname":"iPhone","status":"0"}, {"ipaddr":"192.168.1.101","macaddr":"0c:xxxxxxx:86","devname":"AMD-Ryzen5","status":"1"}, {"ipaddr":"192.168.1.36","macaddr":"da:xxxxxx:70","devname":"pihole","status":"1"}, {"ipaddr":"192.168.1.108","macaddr":"00:xxxxxxx:c2","devname":"DS216j","status":"1"}, {"ipaddr":"192.168.1.106","macaddr":"6a:xxxxxxx:00","devname":"fhem","status":"0"}, {"ipaddr":"192.168.1.107","macaddr":"a8:xxxxxxx:e3","devname":"Meins Box","status":"1"},

[code] for device in json_response: mac = None name = None online = None

        if "macaddr" in device:
            mac = device.get("macaddr")

        if "devname" in device:
            name = device.get("devname")

        if "status" in device:
            online = device.get("status")

        if mac is not None and name is not None and online is "1":
                devices[mac] = name

    return devices

[/code]

Many thanks

sakowicz commented 11 months ago

Sorry, but I don't have this router now. So I can't test it ☹️.

You can fork the repo and try to implement your customization by yourself. It doesn't sound complicated I think you will handle this 😉

cs301cs301 commented 10 months ago

I actually managed to do it myself, but had to switch on debug logging to detect the problems. Now the Tenda plugin works and shows all devices with "status"= 1 in the "bindList".

import hashlib
import json
import logging
from time import time
import homeassistant.helpers.config_validation as cv
import requests
import voluptuous as vol
from homeassistant.components.device_tracker import (
    DOMAIN,
    PLATFORM_SCHEMA,
    DeviceScanner,
)
from homeassistant.const import (
    CONF_HOST,
    CONF_PASSWORD,
)

_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,
    }
)

def get_scanner(hass, config):
    scanner = TendaDeviceScanner(config[DOMAIN])
    if scanner.is_initialized:
        return scanner
    return None

class TendaDeviceScanner(DeviceScanner):
    def __init__(self, config):
        host = config[CONF_HOST]
        password = config[CONF_PASSWORD]
        self.is_initialized = False
        self.last_results = {}

        try:
            self.tenda_client = TendaClient(host, password)
            self._update_info()
            self.is_initialized = True
        except requests.exceptions.ConnectionError:
            _LOGGER.error("Cannot connect to tenda device")

    def scan_devices(self):
        _LOGGER.debug("Scanning devices...")
        self._update_info()
        return self.last_results

    def get_device_name(self, device):
        return self.last_results.get(device)

    def _update_info(self):
        _LOGGER.debug("Loading wireless clients...")
        self.last_results = self.tenda_client.get_connected_devices()

class TendaClient:
    def __init__(self, host: str, password: str) -> None:
        self.host = host
        self.password = password
        self.cookies = None
        self.is_authorized = None

    def auth(self):
        _LOGGER.debug("Trying to authorize")
        headers = {
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        }

        data = (
                "username=admin&password=" + hashlib.md5(self.password.encode()).hexdigest()
        )
        response = requests.post(
            "http://" + self.host + "/login/Auth",
            headers=headers,
            data=data,
            verify=False,
            allow_redirects=False,
        )
        self.cookies = response.cookies
        self.cookies = response.cookies

    def get_connected_devices(self):
        if self.cookies is None:
            _LOGGER.debug("Cookies not found")
            self.auth()

        response = requests.get(
            "http://" + self.host + "/goform/GetIpMacBind?" + str(time()),
            verify=False,
            cookies=self.cookies,
            allow_redirects=False,
        )

        try:
            json_response = json.loads(response.content)
        except json.JSONDecodeError:
            self.cookies = None
            return self.get_connected_devices()

        devices = {}

        for device in json_response["bindList"]:
            mac = None
            name = None
            status = None
            _LOGGER.debug(device)
            if "macaddr" in device:
                mac = device.get("macaddr")

            if "devname" in device:
                name = device.get("devname")

            if "status" in device:
                status = device.get("status")

            if status == "1":
                devices[mac] = name

        return devices