"""Support for Netgear routers.""" import logging 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_PORT, CONF_SSL, CONF_DEVICES, CONF_EXCLUDE, ) _LOGGER = logging.getLogger(__name__) CONF_APS = "accesspoints" PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { vol.Optional(CONF_HOST, default=""): cv.string, vol.Optional(CONF_SSL, default=False): cv.boolean, vol.Optional(CONF_USERNAME, default=""): cv.string, vol.Required(CONF_PASSWORD): cv.string, vol.Optional(CONF_PORT, default=None): vol.Any(None, cv.port), vol.Optional(CONF_DEVICES, default=[]): vol.All(cv.ensure_list, [cv.string]), vol.Optional(CONF_EXCLUDE, default=[]): vol.All(cv.ensure_list, [cv.string]), vol.Optional(CONF_APS, default=[]): vol.All(cv.ensure_list, [cv.string]), } ) def get_scanner(hass, config): """Validate the configuration and returns a Netgear scanner.""" info = config[DOMAIN] host = info.get(CONF_HOST) ssl = info.get(CONF_SSL) username = info.get(CONF_USERNAME) password = info.get(CONF_PASSWORD) port = info.get(CONF_PORT) devices = info.get(CONF_DEVICES) excluded_devices = info.get(CONF_EXCLUDE) accesspoints = info.get(CONF_APS) scanner = NetgearDeviceScanner( host, ssl, username, password, port, devices, excluded_devices, accesspoints ) return scanner if scanner.success_init else None class NetgearDeviceScanner(DeviceScanner): """Queries a Netgear wireless router using the SOAP-API.""" def __init__( self, host, ssl, username, password, port, devices, excluded_devices, accesspoints, ): """Initialize the scanner.""" import pynetgear self.tracked_devices = devices self.excluded_devices = excluded_devices self.tracked_accesspoints = accesspoints self.last_results = [] self._api = pynetgear.Netgear(password, host, username, port, ssl) _LOGGER.info("Logging in") results = self.get_attached_devices() self.success_init = results is not None if self.success_init: self.last_results = results else: _LOGGER.error("Failed to Login") def scan_devices(self): """Scan for new devices and return a list with found device IDs.""" self._update_info() devices = [] for dev in self.last_results: tracked = ( not self.tracked_devices or dev.mac in self.tracked_devices or dev.name in self.tracked_devices ) tracked = tracked and ( not self.excluded_devices or not ( dev.mac in self.excluded_devices or dev.name in self.excluded_devices ) ) if tracked: devices.append(dev.mac) if ( self.tracked_accesspoints and dev.conn_ap_mac in self.tracked_accesspoints ): devices.append(dev.mac + "_" + dev.conn_ap_mac) return devices def get_device_name(self, device): """Return the name of the given device or the MAC if we don't know.""" parts = device.split("_") mac = parts[0] ap_mac = None if len(parts) > 1: ap_mac = parts[1] name = None for dev in self.last_results: if dev.mac == mac: name = dev.name break if not name or name == "--": name = mac if ap_mac: ap_name = "Router" for dev in self.last_results: if dev.mac == ap_mac: ap_name = dev.name break return name + " on " + ap_name return name def _update_info(self): """Retrieve latest information from the Netgear router. Returns boolean if scanning successful. """ if not self.success_init: return _LOGGER.info("Scanning") results = self.get_attached_devices() if results is None: _LOGGER.warning("Error scanning devices") self.last_results = results or [] def get_attached_devices(self): """ List attached devices with pynetgear. The v2 method takes more time and is more heavy on the router so we only use it if we need connected AP info. """ if self.tracked_accesspoints: return self._api.get_attached_devices_2() return self._api.get_attached_devices()