diff --git a/homeassistant/components/device_tracker/nmap_tracker.py b/homeassistant/components/device_tracker/nmap_tracker.py index e23d5f31145..19bc32965e0 100644 --- a/homeassistant/components/device_tracker/nmap_tracker.py +++ b/homeassistant/components/device_tracker/nmap_tracker.py @@ -10,11 +10,13 @@ import subprocess from collections import namedtuple from datetime import timedelta +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv import homeassistant.util.dt as dt_util -from homeassistant.components.device_tracker import DOMAIN +from homeassistant.components.device_tracker import DOMAIN, PLATFORM_SCHEMA from homeassistant.const import CONF_HOSTS -from homeassistant.helpers import validate_config -from homeassistant.util import Throttle, convert +from homeassistant.util import Throttle # Return cached results if last scan was less then this time ago MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) @@ -27,18 +29,21 @@ CONF_EXCLUDE = 'exclude' REQUIREMENTS = ['python-nmap==0.6.1'] +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_HOSTS): vol.All(cv.ensure_list, [cv.string]), + vol.Required(CONF_HOME_INTERVAL, default=0): cv.positive_int, + vol.Optional(CONF_EXCLUDE, default=[]): + vol.All(cv.ensure_list, vol.Length(min=1)) +}) + def get_scanner(hass, config): """Validate the configuration and return a Nmap scanner.""" - if not validate_config(config, {DOMAIN: [CONF_HOSTS]}, - _LOGGER): - return None - scanner = NmapDeviceScanner(config[DOMAIN]) return scanner if scanner.success_init else None -Device = namedtuple("Device", ["mac", "name", "ip", "last_update"]) +Device = namedtuple('Device', ['mac', 'name', 'ip', 'last_update']) def _arp(ip_address): @@ -49,24 +54,26 @@ def _arp(ip_address): match = re.search(r'(([0-9A-Fa-f]{1,2}\:){5}[0-9A-Fa-f]{1,2})', str(out)) if match: return match.group(0) - _LOGGER.info("No MAC address found for %s", ip_address) + _LOGGER.info('No MAC address found for %s', ip_address) return None class NmapDeviceScanner(object): """This class scans for devices using nmap.""" + exclude = [] + def __init__(self, config): """Initialize the scanner.""" self.last_results = [] self.hosts = config[CONF_HOSTS] self.exclude = config.get(CONF_EXCLUDE, []) - minutes = convert(config.get(CONF_HOME_INTERVAL), int, 0) + minutes = config[CONF_HOME_INTERVAL] self.home_interval = timedelta(minutes=minutes) self.success_init = self._update_info() - _LOGGER.info("nmap scanner initialized") + _LOGGER.info('nmap scanner initialized') def scan_devices(self): """Scan for new devices and return a list with found device IDs.""" @@ -90,21 +97,18 @@ class NmapDeviceScanner(object): Returns boolean if scanning successful. """ - _LOGGER.info("Scanning") + _LOGGER.info('Scanning') from nmap import PortScanner, PortScannerError scanner = PortScanner() - options = "-F --host-timeout 5s " - exclude = "--exclude " + options = '-F --host-timeout 5s ' if self.home_interval: boundary = dt_util.now() - self.home_interval last_results = [device for device in self.last_results if device.last_update > boundary] if last_results: - # Pylint is confused here. - # pylint: disable=no-member exclude_hosts = self.exclude + [device.ip for device in last_results] else: @@ -113,8 +117,7 @@ class NmapDeviceScanner(object): last_results = [] exclude_hosts = self.exclude if exclude_hosts: - exclude = " --exclude {}".format(",".join(exclude_hosts)) - options += exclude + options += ' --exclude {}'.format(','.join(exclude_hosts)) try: result = scanner.scan(hosts=self.hosts, arguments=options) @@ -134,5 +137,5 @@ class NmapDeviceScanner(object): self.last_results = last_results - _LOGGER.info("nmap scan successful") + _LOGGER.info('nmap scan successful') return True diff --git a/homeassistant/components/device_tracker/thomson.py b/homeassistant/components/device_tracker/thomson.py index be3249c8b00..cf8f808f82a 100644 --- a/homeassistant/components/device_tracker/thomson.py +++ b/homeassistant/components/device_tracker/thomson.py @@ -10,9 +10,11 @@ import telnetlib import threading from datetime import timedelta -from homeassistant.components.device_tracker import DOMAIN +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.components.device_tracker import DOMAIN, PLATFORM_SCHEMA from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME -from homeassistant.helpers import validate_config from homeassistant.util import Throttle # Return cached results if last scan was less then this time ago. @@ -21,23 +23,24 @@ MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) _LOGGER = logging.getLogger(__name__) _DEVICES_REGEX = re.compile( - r'(?P(([0-9a-f]{2}[:-]){5}([0-9a-f]{2})))\s' + - r'(?P([0-9]{1,3}[\.]){3}[0-9]{1,3})\s+' + - r'(?P([^\s]+))\s+' + - r'(?P([^\s]+))\s+' + - r'(?P([^\s]+))\s+' + - r'(?P([^\s]+))\s+' + + r'(?P(([0-9a-f]{2}[:-]){5}([0-9a-f]{2})))\s' + r'(?P([0-9]{1,3}[\.]){3}[0-9]{1,3})\s+' + r'(?P([^\s]+))\s+' + r'(?P([^\s]+))\s+' + r'(?P([^\s]+))\s+' + r'(?P([^\s]+))\s+' r'(?P([^\s]+))') +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_HOST): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + vol.Required(CONF_USERNAME): cv.string +}) + # pylint: disable=unused-argument def get_scanner(hass, config): """Validate the configuration and return a THOMSON scanner.""" - if not validate_config(config, - {DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]}, - _LOGGER): - return None - scanner = ThomsonDeviceScanner(config[DOMAIN]) return scanner if scanner.success_init else None @@ -84,7 +87,7 @@ class ThomsonDeviceScanner(object): return False with self.lock: - _LOGGER.info("Checking ARP") + _LOGGER.info('Checking ARP') data = self.get_thomson_data() if not data: return False @@ -108,11 +111,11 @@ class ThomsonDeviceScanner(object): devices_result = telnet.read_until(b'=>').split(b'\r\n') telnet.write('exit\r\n'.encode('ascii')) except EOFError: - _LOGGER.exception("Unexpected response from router") + _LOGGER.exception('Unexpected response from router') return except ConnectionRefusedError: - _LOGGER.exception("Connection refused by router," + - " is telnet enabled?") + _LOGGER.exception('Connection refused by router,' + ' is telnet enabled?') return devices = {} diff --git a/homeassistant/components/device_tracker/tplink.py b/homeassistant/components/device_tracker/tplink.py index ad295099bf5..3e691a7149d 100755 --- a/homeassistant/components/device_tracker/tplink.py +++ b/homeassistant/components/device_tracker/tplink.py @@ -12,10 +12,11 @@ import threading from datetime import timedelta import requests +import voluptuous as vol -from homeassistant.components.device_tracker import DOMAIN +import homeassistant.helpers.config_validation as cv +from homeassistant.components.device_tracker import DOMAIN, PLATFORM_SCHEMA from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME -from homeassistant.helpers import validate_config from homeassistant.util import Throttle # Return cached results if last scan was less then this time ago @@ -23,26 +24,22 @@ MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) _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 TP-Link scanner.""" - if not validate_config(config, - {DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]}, - _LOGGER): - return None + for cls in [Tplink4DeviceScanner, Tplink3DeviceScanner, + Tplink2DeviceScanner, TplinkDeviceScanner]: + scanner = cls(config[DOMAIN]) + if scanner.success_init: + return scanner - scanner = Tplink4DeviceScanner(config[DOMAIN]) - - if not scanner.success_init: - scanner = Tplink3DeviceScanner(config[DOMAIN]) - - if not scanner.success_init: - scanner = Tplink2DeviceScanner(config[DOMAIN]) - - if not scanner.success_init: - scanner = TplinkDeviceScanner(config[DOMAIN]) - - return scanner if scanner.success_init else None + return None class TplinkDeviceScanner(object):