Hi,
I have a problem with the device tracker for the Tenda router. The actual integration is from the HACS Store and for the Tenda AC23 router. It also works with my Tenda RX3 router. However, the integration uses /goform/getOnlineList? to query the connected devices. But this is the list for the known devices, not for the currently available ones. As the devices are known to the router, they are always displayed as online/present.
You can get the actual list of available devices via /goform/GetIpMacBind?
There you get the following list:
{"lanIp":"192.168.1.35","lanMask":"255.255.255.0","dhttpIP":"0.0.0.0","dhcpClientList":[{"ipaddr":"192.168.1.229","macaddr":"01:02:03:04:05:06","devname":"homeassistant","status":"1"}, {"ipaddr":"192.168.1.101","macaddr":"01:02:03:04:05:06","devname":"AMD-Ryzen5","status":"1"}, {"ipaddr":"192.168.1.125","macaddr":"01:02:03:04:05:06","devname":"HF-LPB130","status":"1"}, {"ipaddr":"192.168.1.107","macaddr":"01:02:03:04:05:06","devname":"Coreelec","status":"1"}, {"ipaddr":"192.168.1.216","macaddr":"01:02:03:04:05:06","devname":"CoreELEC","status":"1"}, {"ipaddr":"192.168.1.238","macaddr":"01:02:03:04:05:06","devname":"pihole","status":"1"}, {"ipaddr":"192.168.1.252","macaddr":"01:02:03:04:05:06","devname":"klipper","status":"1"}, {"ipaddr":"192.168.1.225","macaddr":"01:02:03:04:05:06","devname":"Echo Flex","status":"1"}, {"ipaddr":"192.168.1.139","macaddr":"01:02:03:04:05:06","devname":"HF-LPB130","status":"1"}],"bindList":[{"ipaddr":"192.168.1.142","macaddr":"01:02:03:04:05:06","devname":"iPhone","status":"1"}, {"ipaddr":"192.168.1.165","macaddr":"01:02:03:04:05:06","devname":"Mi9TPro","status":"1"}, {"ipaddr":"192.168.1.201","macaddr":"01:02:03:04:05:06","devname":"Lampe","status":"1"}, {"ipaddr":"192.168.1.202","macaddr":"01:02:03:04:05:06","devname":"Steckdose","status":"1"}, {"ipaddr":"192.168.1.200","macaddr":"01:02:03:04:05:06","devname":"Licht","status":"1"}, {"ipaddr":"192.168.1.108","macaddr":"01:02:03:04:05:06","devname":"DS216j","status":"1"}]}
“status” 0/1 indicates whether the known device is really online.
I have tried to adapt the actual script, but without success. The devices are always shown as absent.
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
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
devname = None
status = None
if "macaddr" in device:
mac = device.get("macaddr")
if "devname" in device:
devname = device.get("devname")
if "status" in device:
status = device.get("status")
if mac is not None and devname is not None and status == "1":
devices[mac] = devname
return devices
Could someone help me with this? Unfortunately I am not a software developer.
I’m glad that I created this working standalone Python script to show me the available devices.
import requests
import hashlib
from time import time
import json
def get_connected_devices(host, password):
"""
Ermittelt eine Liste der verbundenen Geräte an einem Tenda-Router.
Args:
host: Die IP-Adresse des Tenda-Routers.
password: Das Passwort des Tenda-Routers.
Returns:
Eine Liste der verbundenen Geräte.
"""
# Authentifiziere dich beim Router.
headers = {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
}
data = (
"username=admin&password=" + hashlib.md5(password.encode()).hexdigest()
)
response = requests.post(
"http://" + host + "/login/Auth",
headers=headers,
data=data,
verify=False,
allow_redirects=False,
)
response = requests.post(
"http://" + host + "/login/Auth",
headers=headers,
data=data,
verify=False,
allow_redirects=False,
)
# Speichere die Cookies.
cookies = response.cookies
# Erhalte die Liste der verbundenen Geräte.
response = requests.get(
"http://" + host + "/goform/GetIpMacBind?" + str(time()),
verify=False,
cookies=cookies,
allow_redirects=False,
)
# Dekodiere die Antwort.
try:
json_response = json.loads(response.content)
except json.JSONDecodeError:
return {}
# Gib die Liste der verbundenen Geräte zurück.
return json_response["bindList"]
if __name__ == "__main__":
# Gib die Liste der verbundenen Geräte aus.
host = "192.168.1.35"
password = "password"
devices = get_connected_devices(host, password)
for device in devices:
if device["status"] == "1":
print("Gerät: %s - MAC: %s" % (device["devname"],device["macaddr"]))