I have been using the Experiabox V10 device tracker for some time and I was pretty happy with it. But to get better wifi coverage I got two Experia Wifi access points from my internet provider. These access points disable wifi on the Experiabox router, so that device trackers doesn’t work anymore.
So I am trying to create a device tracker for those access points. As they are also Arcadyan branded, like the Experiabox v8, I tried to use the device tracker for that router as a basis.
When logging in to the web interface of one of the access points I can see a POST to /login.cgi with the following data:
‘pws’ is a MD5 hash of the password. ‘httoken’ is a decoded Base64 string that’s in the source code of the login page /login.htm “disguised” in some html looking like this:
<img title=spacer src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7MjgzNTY3Njg3" border=0>
Where MjgzNTY3Njg3 is the Base64 string, which changed on reload of the page.
While I have no experience nor knowledge of Python, I tried to alter the code from the Experiabox v8 to work with the Experia Wifi access points.
"""
Support for Experia Wifi access point
"""
import base64
import hashlib
import logging
import re
from datetime import datetime
import requests
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.components.device_tracker import (
DOMAIN, PLATFORM_SCHEMA, DeviceScanner)
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
_LOGGER = logging.getLogger(__name__)
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 Arcadyan AP scanner."""
try:
return ArcadyanDeviceScanner(config[DOMAIN])
except ConnectionError:
return None
class ArcadyanDeviceScanner(DeviceScanner):
"""This class queries a wireless router running Arcadyan 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 Arcadyan router is up to date.
Return boolean if scanning successful.
"""
_LOGGER.info("Loading wireless clients...")
login_url_initial = 'http://{}/login.htm'.format(self.host)
page_initial = requests.get(login_url_initial)
httoken_search = re.search("yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'(.*)'\" border=0>", page_initial.text)
authenticity_token = base64.b64decode(httoken_search.group(1))
login_payload = {
"httoken": authenticity_token,
"user": self.username,
"pws": self.password
}
# clear_payload = {
# "securityclear.y": "8",
# "securityclear.x": "57",
# "httoken": authenticity_token
# }
login_url = 'http://{}/login.cgi'.format(self.host)
start_page = requests.post(login_url, data = login_payload)
# clear_url = 'http://{}/cgi-bin/statusprocess.exe'.format(self.host)
# clear_log = requests.post(clear_url, data = clear_payload)
data_url = 'http://{}/connected_client.htm'.format(self.host)
data_page = requests.get(data_url)
result = self.parse_macs.findall(data_page.text)
logout_url_initial = 'http://{}/setup_top.htm'.format(self.host)
page2_initial = requests.get(logout_url_initial)
httoken2_search = re.search("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'(.*)'\" border=0>", page2_initial.text)
authenticity_token2 = base64.b64decode(httoken2_search.group(1))
logout_payload = {
"httoken": authenticity_token2,
}
logout_url = 'http://{}/logout.cgi'.format(self.host)
log_out_page = requests.post(logout_url, data = logout_payload)
if result:
self.last_results = [mac.replace("-", ":") for mac in result]
return True
return False
I believe the logout uses a similar string for httoken from /setup_top.htm.
I am realistic but I still tried this device tracker in my custom_components. Rebooting took forever and all other device trackers were broken after the reboot (as in not working). Disabling the component fixed the device trackers again. Log didn’t show something relevant.
So my question would be: how would I go about debugging? Where/how can I properly test this code? Could someone maybe help me with this?