From 951372491c160e0fa766afff175be7609e0510f6 Mon Sep 17 00:00:00 2001 From: Andrey Kupreychik <foxel@quickfox.ru> Date: Tue, 31 Jul 2018 16:14:49 +0700 Subject: [PATCH] Fixed NDMS for latest firmware (#15511) * Fixed NDMS for latest firmware. Now using telnet instead of Web Interface * Using external library for NDMS interactions * updated requirements_all * renamed `mac` to `device` back * Using generators for name and attributes fetching --- .../device_tracker/keenetic_ndms2.py | 88 ++++++++----------- requirements_all.txt | 3 + 2 files changed, 38 insertions(+), 53 deletions(-) diff --git a/homeassistant/components/device_tracker/keenetic_ndms2.py b/homeassistant/components/device_tracker/keenetic_ndms2.py index 36dc1182a92..4b5e3d6333d 100644 --- a/homeassistant/components/device_tracker/keenetic_ndms2.py +++ b/homeassistant/components/device_tracker/keenetic_ndms2.py @@ -5,18 +5,18 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/device_tracker.keenetic_ndms2/ """ import logging -from collections import namedtuple -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_HOST, CONF_PORT, CONF_PASSWORD, CONF_USERNAME ) +REQUIREMENTS = ['ndms2_client==0.0.3'] + _LOGGER = logging.getLogger(__name__) # Interface name to track devices for. Most likely one will not need to @@ -25,11 +25,13 @@ _LOGGER = logging.getLogger(__name__) CONF_INTERFACE = 'interface' DEFAULT_INTERFACE = 'Home' +DEFAULT_PORT = 23 PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PORT, default=DEFAULT_PORT): cv.port, vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_INTERFACE, default=DEFAULT_INTERFACE): cv.string, }) @@ -42,21 +44,22 @@ def get_scanner(_hass, config): return scanner if scanner.success_init else None -Device = namedtuple('Device', ['mac', 'name']) - - class KeeneticNDMS2DeviceScanner(DeviceScanner): """This class scans for devices using keenetic NDMS2 web interface.""" def __init__(self, config): """Initialize the scanner.""" + from ndms2_client import Client, TelnetConnection self.last_results = [] - self._url = 'http://%s/rci/show/ip/arp' % config[CONF_HOST] self._interface = config[CONF_INTERFACE] - self._username = config.get(CONF_USERNAME) - self._password = config.get(CONF_PASSWORD) + self._client = Client(TelnetConnection( + config.get(CONF_HOST), + config.get(CONF_PORT), + config.get(CONF_USERNAME), + config.get(CONF_PASSWORD), + )) self.success_init = self._update_info() _LOGGER.info("Scanner initialized") @@ -69,53 +72,32 @@ class KeeneticNDMS2DeviceScanner(DeviceScanner): def get_device_name(self, device): """Return the name of the given device or None if we don't know.""" - filter_named = [result.name for result in self.last_results - if result.mac == device] - - if filter_named: - return filter_named[0] - return None + name = next(( + result.name for result in self.last_results + if result.mac == device), None) + return name + + def get_extra_attributes(self, device): + """Return the IP of the given device.""" + attributes = next(( + {'ip': result.ip} for result in self.last_results + if result.mac == device), {}) + return attributes def _update_info(self): """Get ARP from keenetic router.""" - _LOGGER.info("Fetching...") - - last_results = [] + _LOGGER.debug("Fetching devices from router...") - # doing a request - try: - from requests.auth import HTTPDigestAuth - res = requests.get(self._url, timeout=10, auth=HTTPDigestAuth( - self._username, self._password - )) - except requests.exceptions.Timeout: - _LOGGER.error( - "Connection to the router timed out at URL %s", self._url) - return False - if res.status_code != 200: - _LOGGER.error( - "Connection failed with http code %s", res.status_code) - return False + from ndms2_client import ConnectionException try: - result = res.json() - except ValueError: - # If json decoder could not parse the response - _LOGGER.error("Failed to parse response from router") + self.last_results = [ + dev + for dev in self._client.get_devices() + if dev.interface == self._interface + ] + _LOGGER.debug("Successfully fetched data from router") + return True + + except ConnectionException: + _LOGGER.error("Error fetching data from router") return False - - # parsing response - for info in result: - if info.get('interface') != self._interface: - continue - mac = info.get('mac') - name = info.get('name') - # No address = no item :) - if mac is None: - continue - - last_results.append(Device(mac.upper(), name)) - - self.last_results = last_results - - _LOGGER.info("Request successful") - return True diff --git a/requirements_all.txt b/requirements_all.txt index eda2b604115..6dae4f9c44c 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -579,6 +579,9 @@ nad_receiver==0.0.9 # homeassistant.components.light.nanoleaf_aurora nanoleaf==0.4.1 +# homeassistant.components.device_tracker.keenetic_ndms2 +ndms2_client==0.0.3 + # homeassistant.components.sensor.netdata netdata==0.1.2 -- GitLab