Advertisement
techblog

arpscan_tracker.py

Jun 20th, 2018
2,886
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.28 KB | None | 0 0
  1. """
  2. Support for scanning a network with arp-scan.
  3. For more details about this platform, please refer to the documentation at
  4. https://home-assistant.io/components/device_tracker.arpscan_tracker/
  5. """
  6. import logging
  7. import re
  8. import subprocess
  9. from collections import namedtuple
  10. from datetime import timedelta
  11.  
  12. import voluptuous as vol
  13.  
  14. import homeassistant.helpers.config_validation as cv
  15. import homeassistant.util.dt as dt_util
  16. from homeassistant.components.device_tracker import (
  17.     DOMAIN, PLATFORM_SCHEMA, DeviceScanner)
  18. from homeassistant.util import Throttle
  19.  
  20. _LOGGER = logging.getLogger(__name__)
  21.  
  22. CONF_EXCLUDE = 'exclude'
  23. CONF_OPTIONS = 'scan_options'
  24. DEFAULT_OPTIONS = '-l -g -t1 -q'
  25.  
  26. MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5)
  27.  
  28. PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
  29.     vol.Optional(CONF_EXCLUDE, default=[]):
  30.         vol.All(cv.ensure_list, [cv.string]),
  31.     vol.Optional(CONF_OPTIONS, default=DEFAULT_OPTIONS):
  32.         cv.string
  33. })
  34.  
  35.  
  36. def get_scanner(hass, config):
  37.     """Validate the configuration and return a ArpScan scanner."""
  38.     scanner = ArpScanDeviceScanner(config[DOMAIN])
  39.  
  40.     return scanner if scanner.success_init else None
  41.  
  42.  
  43. Device = namedtuple('Device', ['mac', 'name', 'ip', 'last_update'])
  44.  
  45.  
  46. class ArpScanDeviceScanner(DeviceScanner):
  47.     """This class scans for devices using arp-scan."""
  48.  
  49.     exclude = []
  50.  
  51.     def __init__(self, config):
  52.         """Initialize the scanner."""
  53.         self.last_results = []
  54.  
  55.         self.exclude = config[CONF_EXCLUDE]
  56.         self._options = config[CONF_OPTIONS]
  57.  
  58.         self.success_init = self._update_info()
  59.         _LOGGER.debug("Init called")
  60.  
  61.     def scan_devices(self):
  62.         """Scan for new devices and return a list with found device IDs."""
  63.         self._update_info()
  64.  
  65.         _LOGGER.debug("Scan devices called")
  66.         return [device.mac for device in self.last_results]
  67.  
  68.     def get_device_name(self, mac):
  69.         """Return the name of the given device or None if we don't know."""
  70.         filter_named = [device.name for device in self.last_results
  71.                         if device.mac == mac]
  72.  
  73.         if filter_named:
  74.             _LOGGER.debug("Filter named called")
  75.             return filter_named[0]
  76.         else:
  77.             return None
  78.  
  79.     @Throttle(MIN_TIME_BETWEEN_SCANS)
  80.     def _update_info(self):
  81.         """Scan the network for devices.
  82.        Returns boolean if scanning successful.
  83.        """
  84.         _LOGGER.debug("Update_info called")
  85.  
  86.         options = self._options
  87.  
  88.         last_results = []
  89.         exclude_hosts = self.exclude
  90.  
  91.         scandata = subprocess.getoutput("arp-scan "+options)
  92.  
  93.         now = dt_util.now()
  94.         for line in scandata.splitlines():
  95.             ipv4 = re.findall(r'[0-9]+(?:\.[0-9]+){3}', line)
  96.             if not ipv4:
  97.                 continue
  98.  
  99.             parts = line.split()
  100.             ipv4 = parts[0]
  101.             for exclude in exclude_hosts:
  102.                 if exclude == ipv4:
  103.                     _LOGGER.debug("Excluded %s", exclude)
  104.                     continue
  105.  
  106.             name = ipv4
  107.             mac = parts[1]
  108.             last_results.append(Device(mac, name, ipv4, now))
  109.  
  110.         self.last_results = last_results
  111.  
  112.         _LOGGER.debug("Update_info successful")
  113.         return True
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement