2016-02-19 23:19:03 +00:00
|
|
|
"""
|
2016-03-07 17:12:06 +00:00
|
|
|
Support for Unifi WAP controllers.
|
|
|
|
|
|
|
|
For more details about this platform, please refer to the documentation at
|
|
|
|
https://home-assistant.io/components/device_tracker.unifi/
|
2016-02-19 23:19:03 +00:00
|
|
|
"""
|
|
|
|
import logging
|
2017-10-13 08:13:58 +00:00
|
|
|
from datetime import timedelta
|
2016-09-04 08:06:16 +00:00
|
|
|
import voluptuous as vol
|
2016-02-19 23:19:03 +00:00
|
|
|
|
2016-09-04 08:06:16 +00:00
|
|
|
import homeassistant.helpers.config_validation as cv
|
2017-01-02 19:50:42 +00:00
|
|
|
from homeassistant.components.device_tracker import (
|
|
|
|
DOMAIN, PLATFORM_SCHEMA, DeviceScanner)
|
2016-02-19 23:19:03 +00:00
|
|
|
from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
|
2017-03-10 10:15:21 +00:00
|
|
|
from homeassistant.const import CONF_VERIFY_SSL
|
2017-10-13 08:13:58 +00:00
|
|
|
import homeassistant.util.dt as dt_util
|
2016-02-19 23:19:03 +00:00
|
|
|
|
2017-06-17 18:09:27 +00:00
|
|
|
REQUIREMENTS = ['pyunifi==2.13']
|
2016-04-21 14:56:19 +00:00
|
|
|
|
2016-02-19 23:19:03 +00:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
CONF_PORT = 'port'
|
2016-07-04 15:20:00 +00:00
|
|
|
CONF_SITE_ID = 'site_id'
|
2017-10-13 08:13:58 +00:00
|
|
|
CONF_DETECTION_TIME = 'detection_time'
|
2018-02-12 07:23:53 +00:00
|
|
|
CONF_SSID_FILTER = 'ssid_filter'
|
2017-04-30 05:04:49 +00:00
|
|
|
|
|
|
|
DEFAULT_HOST = 'localhost'
|
|
|
|
DEFAULT_PORT = 8443
|
2017-03-10 10:15:21 +00:00
|
|
|
DEFAULT_VERIFY_SSL = True
|
2017-10-13 08:13:58 +00:00
|
|
|
DEFAULT_DETECTION_TIME = timedelta(seconds=300)
|
2018-02-12 07:23:53 +00:00
|
|
|
DEFAULT_SSID_FILTER = None
|
2016-02-19 23:19:03 +00:00
|
|
|
|
2016-12-04 06:11:52 +00:00
|
|
|
NOTIFICATION_ID = 'unifi_notification'
|
|
|
|
NOTIFICATION_TITLE = 'Unifi Device Tracker Setup'
|
|
|
|
|
2016-09-04 08:06:16 +00:00
|
|
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
2017-04-30 05:04:49 +00:00
|
|
|
vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string,
|
2016-09-04 08:06:16 +00:00
|
|
|
vol.Optional(CONF_SITE_ID, default='default'): cv.string,
|
|
|
|
vol.Required(CONF_PASSWORD): cv.string,
|
|
|
|
vol.Required(CONF_USERNAME): cv.string,
|
2017-04-30 05:04:49 +00:00
|
|
|
vol.Required(CONF_PORT, default=DEFAULT_PORT): cv.port,
|
2017-10-10 22:08:36 +00:00
|
|
|
vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): vol.Any(
|
2017-10-13 08:13:58 +00:00
|
|
|
cv.boolean, cv.isfile),
|
|
|
|
vol.Optional(CONF_DETECTION_TIME, default=DEFAULT_DETECTION_TIME): vol.All(
|
2018-02-12 07:23:53 +00:00
|
|
|
cv.time_period, cv.positive_timedelta),
|
|
|
|
vol.Optional(CONF_SSID_FILTER, default=DEFAULT_SSID_FILTER): vol.All(
|
|
|
|
cv.ensure_list, [cv.string])
|
2016-09-04 08:06:16 +00:00
|
|
|
})
|
|
|
|
|
2016-02-19 23:19:03 +00:00
|
|
|
|
|
|
|
def get_scanner(hass, config):
|
2017-04-30 05:04:49 +00:00
|
|
|
"""Set up the Unifi device_tracker."""
|
2017-06-17 18:09:27 +00:00
|
|
|
from pyunifi.controller import Controller, APIError
|
2016-02-19 23:19:03 +00:00
|
|
|
|
2016-09-04 08:06:16 +00:00
|
|
|
host = config[DOMAIN].get(CONF_HOST)
|
|
|
|
username = config[DOMAIN].get(CONF_USERNAME)
|
|
|
|
password = config[DOMAIN].get(CONF_PASSWORD)
|
|
|
|
site_id = config[DOMAIN].get(CONF_SITE_ID)
|
|
|
|
port = config[DOMAIN].get(CONF_PORT)
|
2017-03-10 10:15:21 +00:00
|
|
|
verify_ssl = config[DOMAIN].get(CONF_VERIFY_SSL)
|
2017-10-13 08:13:58 +00:00
|
|
|
detection_time = config[DOMAIN].get(CONF_DETECTION_TIME)
|
2018-02-12 07:23:53 +00:00
|
|
|
ssid_filter = config[DOMAIN].get(CONF_SSID_FILTER)
|
2016-02-19 23:19:03 +00:00
|
|
|
|
|
|
|
try:
|
2017-03-10 10:15:21 +00:00
|
|
|
ctrl = Controller(host, username, password, port, version='v4',
|
|
|
|
site_id=site_id, ssl_verify=verify_ssl)
|
2017-06-17 18:09:27 +00:00
|
|
|
except APIError as ex:
|
2017-04-30 05:04:49 +00:00
|
|
|
_LOGGER.error("Failed to connect to Unifi: %s", ex)
|
2017-07-16 19:39:38 +00:00
|
|
|
hass.components.persistent_notification.create(
|
|
|
|
'Failed to connect to Unifi. '
|
2016-12-04 06:11:52 +00:00
|
|
|
'Error: {}<br />'
|
|
|
|
'You will need to restart hass after fixing.'
|
|
|
|
''.format(ex),
|
|
|
|
title=NOTIFICATION_TITLE,
|
|
|
|
notification_id=NOTIFICATION_ID)
|
2016-02-19 23:19:03 +00:00
|
|
|
return False
|
|
|
|
|
2018-02-12 07:23:53 +00:00
|
|
|
return UnifiScanner(ctrl, detection_time, ssid_filter)
|
2016-02-19 23:19:03 +00:00
|
|
|
|
|
|
|
|
2017-01-02 19:50:42 +00:00
|
|
|
class UnifiScanner(DeviceScanner):
|
2016-02-19 23:19:03 +00:00
|
|
|
"""Provide device_tracker support from Unifi WAP client data."""
|
2016-03-07 20:18:53 +00:00
|
|
|
|
2018-02-12 07:23:53 +00:00
|
|
|
def __init__(self, controller, detection_time: timedelta,
|
|
|
|
ssid_filter) -> None:
|
2016-03-07 20:18:53 +00:00
|
|
|
"""Initialize the scanner."""
|
2017-10-13 08:13:58 +00:00
|
|
|
self._detection_time = detection_time
|
2016-02-19 23:19:03 +00:00
|
|
|
self._controller = controller
|
2018-02-12 07:23:53 +00:00
|
|
|
self._ssid_filter = ssid_filter
|
2016-02-19 23:19:03 +00:00
|
|
|
self._update()
|
|
|
|
|
|
|
|
def _update(self):
|
2016-03-07 20:18:53 +00:00
|
|
|
"""Get the clients from the device."""
|
2017-06-17 18:09:27 +00:00
|
|
|
from pyunifi.controller import APIError
|
2016-02-19 23:19:03 +00:00
|
|
|
try:
|
|
|
|
clients = self._controller.get_clients()
|
2017-06-17 18:09:27 +00:00
|
|
|
except APIError as ex:
|
2017-04-30 05:04:49 +00:00
|
|
|
_LOGGER.error("Failed to scan clients: %s", ex)
|
2016-02-19 23:19:03 +00:00
|
|
|
clients = []
|
|
|
|
|
2018-02-12 07:23:53 +00:00
|
|
|
# Filter clients to provided SSID list
|
|
|
|
if self._ssid_filter:
|
|
|
|
clients = filter(lambda x: x['essid'] in self._ssid_filter,
|
|
|
|
clients)
|
|
|
|
|
2017-10-13 08:13:58 +00:00
|
|
|
self._clients = {
|
|
|
|
client['mac']: client
|
|
|
|
for client in clients
|
|
|
|
if (dt_util.utcnow() - dt_util.utc_from_timestamp(float(
|
|
|
|
client['last_seen']))) < self._detection_time}
|
2016-02-19 23:19:03 +00:00
|
|
|
|
|
|
|
def scan_devices(self):
|
2016-03-07 20:18:53 +00:00
|
|
|
"""Scan for devices."""
|
2016-02-19 23:19:03 +00:00
|
|
|
self._update()
|
|
|
|
return self._clients.keys()
|
|
|
|
|
2018-02-11 17:20:28 +00:00
|
|
|
def get_device_name(self, device):
|
2016-03-07 20:18:53 +00:00
|
|
|
"""Return the name (if known) of the device.
|
2016-02-19 23:19:03 +00:00
|
|
|
|
|
|
|
If a name has been set in Unifi, then return that, else
|
|
|
|
return the hostname if it has been detected.
|
|
|
|
"""
|
2018-02-11 17:20:28 +00:00
|
|
|
client = self._clients.get(device, {})
|
2016-02-19 23:19:03 +00:00
|
|
|
name = client.get('name') or client.get('hostname')
|
2018-02-11 17:20:28 +00:00
|
|
|
_LOGGER.debug("Device mac %s name %s", device, name)
|
2016-02-19 23:19:03 +00:00
|
|
|
return name
|