From 8852cd0def3de0644f92df029c5aaad6b3256c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Orri?= Date: Sun, 2 Feb 2020 17:26:51 +0100 Subject: [PATCH] Add Salt Fiber Box device tracker (#30986) * Add salt component * Update files from development checklist * Use warning log level when data cannot be retrieved Co-Authored-By: springstan <46536646+springstan@users.noreply.github.com> * Remove empty fields from manifest.json * Remove default arguments for host and username * Bump saltbox library version * Refactor and improve error handling * Dev checklist * Fix linting errors * Check for None and return empty list * Log on debug level instead of info * More compact None checks * Remove redundant None check * Return None on exception but store as empty list * More compact syntax Co-authored-by: springstan <46536646+springstan@users.noreply.github.com> --- .coveragerc | 1 + CODEOWNERS | 1 + homeassistant/components/salt/__init__.py | 1 + .../components/salt/device_tracker.py | 71 +++++++++++++++++++ homeassistant/components/salt/manifest.json | 8 +++ requirements_all.txt | 3 + 6 files changed, 85 insertions(+) create mode 100644 homeassistant/components/salt/__init__.py create mode 100644 homeassistant/components/salt/device_tracker.py create mode 100644 homeassistant/components/salt/manifest.json diff --git a/.coveragerc b/.coveragerc index 27f63c4baae..cc2402e480b 100644 --- a/.coveragerc +++ b/.coveragerc @@ -602,6 +602,7 @@ omit = homeassistant/components/russound_rnet/media_player.py homeassistant/components/sabnzbd/* homeassistant/components/saj/sensor.py + homeassistant/components/salt/device_tracker.py homeassistant/components/satel_integra/* homeassistant/components/scrape/sensor.py homeassistant/components/scsgate/* diff --git a/CODEOWNERS b/CODEOWNERS index 60501876cd9..5a66f80a1d0 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -285,6 +285,7 @@ homeassistant/components/rmvtransport/* @cgtobi homeassistant/components/roomba/* @pschmitt homeassistant/components/safe_mode/* @home-assistant/core homeassistant/components/saj/* @fredericvl +homeassistant/components/salt/* @bjornorri homeassistant/components/samsungtv/* @escoand homeassistant/components/scene/* @home-assistant/core homeassistant/components/scrape/* @fabaff diff --git a/homeassistant/components/salt/__init__.py b/homeassistant/components/salt/__init__.py new file mode 100644 index 00000000000..29c371ece52 --- /dev/null +++ b/homeassistant/components/salt/__init__.py @@ -0,0 +1 @@ +"""The salt component.""" diff --git a/homeassistant/components/salt/device_tracker.py b/homeassistant/components/salt/device_tracker.py new file mode 100644 index 00000000000..7c03403622a --- /dev/null +++ b/homeassistant/components/salt/device_tracker.py @@ -0,0 +1,71 @@ +"""Support for Salt Fiber Box routers.""" +import logging + +from saltbox import RouterLoginException, RouterNotReachableException, SaltBox +import voluptuous as vol + +from homeassistant.components.device_tracker import ( + DOMAIN, + PLATFORM_SCHEMA, + DeviceScanner, +) +from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME +import homeassistant.helpers.config_validation as cv + +_LOGGER = logging.getLogger(__name__) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( + { + vol.Required(CONF_HOST): cv.string, + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + } +) + + +def get_scanner(hass, config): + """Return the Salt device scanner.""" + scanner = SaltDeviceScanner(config[DOMAIN]) + + # Test whether the router is accessible. + data = scanner.get_salt_data() + return scanner if data is not None else None + + +class SaltDeviceScanner(DeviceScanner): + """This class queries a Salt Fiber Box router.""" + + def __init__(self, config): + """Initialize the scanner.""" + host = config[CONF_HOST] + username = config[CONF_USERNAME] + password = config[CONF_PASSWORD] + self.saltbox = SaltBox(f"http://{host}", username, password) + self.online_clients = [] + + def scan_devices(self): + """Scan for new devices and return a list with found device IDs.""" + self._update_info() + return [client["mac"] for client in self.online_clients] + + def get_device_name(self, device): + """Return the name of the given device or None if we don't know.""" + for client in self.online_clients: + if client["mac"] == device: + return client["name"] + return None + + def get_salt_data(self): + """Retrieve data from Salt router and return parsed result.""" + try: + clients = self.saltbox.get_online_clients() + return clients + except (RouterLoginException, RouterNotReachableException) as error: + _LOGGER.warning(error) + return None + + def _update_info(self): + """Pull the current information from the Salt router.""" + _LOGGER.debug("Loading data from Salt Fiber Box") + data = self.get_salt_data() + self.online_clients = data or [] diff --git a/homeassistant/components/salt/manifest.json b/homeassistant/components/salt/manifest.json new file mode 100644 index 00000000000..019fdf9ae5f --- /dev/null +++ b/homeassistant/components/salt/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "salt", + "name": "Salt Fiber Box", + "documentation": "https://www.home-assistant.io/integrations/salt", + "requirements": ["saltbox==0.1.3"], + "dependencies": [], + "codeowners": ["@bjornorri"] +} diff --git a/requirements_all.txt b/requirements_all.txt index da993a0dc16..5847dd784fc 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1782,6 +1782,9 @@ russound_rio==0.1.7 # homeassistant.components.yamaha rxv==0.6.0 +# homeassistant.components.salt +saltbox==0.1.3 + # homeassistant.components.samsungtv samsungctl[websocket]==0.7.1