"""Support for Linksys Access Points.""" import base64 import logging 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, CONF_VERIFY_SSL) INTERFACES = 2 DEFAULT_TIMEOUT = 10 _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, vol.Optional(CONF_VERIFY_SSL, default=True): cv.boolean, }) def get_scanner(hass, config): """Validate the configuration and return a Linksys AP scanner.""" try: return LinksysAPDeviceScanner(config[DOMAIN]) except ConnectionError: return None class LinksysAPDeviceScanner(DeviceScanner): """This class queries a Linksys Access Point.""" def __init__(self, config): """Initialize the scanner.""" self.host = config[CONF_HOST] self.username = config[CONF_USERNAME] self.password = config[CONF_PASSWORD] self.verify_ssl = config[CONF_VERIFY_SSL] self.last_results = [] # Check if the access point is accessible response = self._make_request() if not response.status_code == 200: raise ConnectionError("Cannot connect to Linksys Access Point") def scan_devices(self): """Scan for new devices and return a list with found device IDs.""" self._update_info() return self.last_results def get_device_name(self, device): """ Return the name (if known) of the device. Linksys does not provide an API to get a name for a device, so we just return None """ return None def _update_info(self): """Check for connected devices.""" from bs4 import BeautifulSoup as BS _LOGGER.info("Checking Linksys AP") self.last_results = [] for interface in range(INTERFACES): request = self._make_request(interface) self.last_results.extend( [x.find_all('td')[1].text for x in BS(request.content, 'html.parser') .find_all(class_='section-row')] ) return True def _make_request(self, unit=0): """Create a request to get the data.""" # No, the '&&' is not a typo - this is expected by the web interface. login = base64.b64encode(bytes(self.username, 'utf8')).decode('ascii') pwd = base64.b64encode(bytes(self.password, 'utf8')).decode('ascii') url = 'https://{}/StatusClients.htm&&unit={}&vap=0'.format( self.host, unit) return requests.get( url, timeout=DEFAULT_TIMEOUT, verify=self.verify_ssl, cookies={'LoginName': login, 'LoginPWD': pwd})