From f5d0f36caf878bde01286f11f52daa257a7bb403 Mon Sep 17 00:00:00 2001 From: Kim Frellsen Date: Wed, 24 Jul 2019 01:18:58 +0200 Subject: [PATCH] Add new device tracker supporting Fortinet FortiGate (#23078) * Create device_tracker.py initial version * Update device_tracker.py set verify SSL to false as default. Normally users do not have a verified certificate at home * Update device_tracker.py pep8 compliant * Update device_tracker.py upgraded fortiosapi requirements * Create __init__.py * tox compliant * Update device_tracker.py * Create manifest.json * Update .coveragerc added fortios * Update device_tracker.py circle ci, blank line required * Update manifest.json removed code owners * Update manifest.json removed dependencies * Update manifest.json removed codeowners * Update requirements_all.txt added fortios * Update requirements_all.txt * Update device_tracker.py pylint corrections * Update device_tracker.py pylint exceptions * Update device_tracker.py disable pylint broad exceptions * Update device_tracker.py pylint * Update device_tracker.py removed pointless string statements * Update device_tracker.py removed blank line * Update device_tracker.py * Update device_tracker.py * Update device_tracker.py * Update device_tracker.py * Update device_tracker.py * Update device_tracker.py * Update device_tracker.py * Update device_tracker.py * Update device_tracker.py * Update device_tracker.py * Update device_tracker.py * Update device_tracker.py * Update device_tracker.py * Update manifest.json added codeowners * Update CODEOWNERS added kimfrellsen as codeowner * fortiosapi 0.10.8 Updated to use latest version of fortiosapi 0.10.8 * Update requirements_all.txt updated fortiosapi to 0.10.8 * Update device_tracker.py fixed some requests. * Update device_tracker.py better exception handling. * Update device_tracker.py exception handling * Update CODEOWNERS * Update device_tracker.py corrected exception handling * Update device_tracker.py exception handling. * Update device_tracker.py lint corrections * Update device_tracker.py removed broad exception. * Update device_tracker.py fix lint errors * Update device_tracker.py minor changes, mostly cosmetic --- .coveragerc | 1 + CODEOWNERS | 1 + homeassistant/components/fortios/__init__.py | 1 + .../components/fortios/device_tracker.py | 97 +++++++++++++++++++ .../components/fortios/manifest.json | 10 ++ requirements_all.txt | 3 + 6 files changed, 113 insertions(+) create mode 100644 homeassistant/components/fortios/__init__.py create mode 100755 homeassistant/components/fortios/device_tracker.py create mode 100644 homeassistant/components/fortios/manifest.json diff --git a/.coveragerc b/.coveragerc index ac3baed48b0..16c87ea4d47 100644 --- a/.coveragerc +++ b/.coveragerc @@ -211,6 +211,7 @@ omit = homeassistant/components/folder/sensor.py homeassistant/components/folder_watcher/* homeassistant/components/foobot/sensor.py + homeassistant/components/fortios/device_tracker.py homeassistant/components/fortigate/* homeassistant/components/foscam/camera.py homeassistant/components/foursquare/* diff --git a/CODEOWNERS b/CODEOWNERS index 7acd04ea366..91bf80f9d33 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -94,6 +94,7 @@ homeassistant/components/fixer/* @fabaff homeassistant/components/flock/* @fabaff homeassistant/components/flunearyou/* @bachya homeassistant/components/fortigate/* @kifeo +homeassistant/components/fortios/* @kimfrellsen homeassistant/components/foursquare/* @robbiet480 homeassistant/components/freebox/* @snoof85 homeassistant/components/fronius/* @nielstron diff --git a/homeassistant/components/fortios/__init__.py b/homeassistant/components/fortios/__init__.py new file mode 100644 index 00000000000..873d6c00c65 --- /dev/null +++ b/homeassistant/components/fortios/__init__.py @@ -0,0 +1 @@ +"""Fortinet FortiOS components.""" diff --git a/homeassistant/components/fortios/device_tracker.py b/homeassistant/components/fortios/device_tracker.py new file mode 100755 index 00000000000..b5ed538ec41 --- /dev/null +++ b/homeassistant/components/fortios/device_tracker.py @@ -0,0 +1,97 @@ +""" +Support to use FortiOS device like FortiGate as device tracker. + +This component is part of the device_tracker platform. +""" +import logging + +import voluptuous as vol +from fortiosapi import FortiOSAPI + +import homeassistant.helpers.config_validation as cv +from homeassistant.components.device_tracker import ( + DOMAIN, PLATFORM_SCHEMA, DeviceScanner) +from homeassistant.const import CONF_HOST, CONF_TOKEN +from homeassistant.const import CONF_VERIFY_SSL + +_LOGGER = logging.getLogger(__name__) +DEFAULT_VERIFY_SSL = False + + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_HOST): cv.string, + vol.Required(CONF_TOKEN): cv.string, + vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean +}) + + +def get_scanner(hass, config): + """Validate the configuration and return a FortiOSDeviceScanner.""" + + host = config[DOMAIN][CONF_HOST] + verify_ssl = config[DOMAIN][CONF_VERIFY_SSL] + token = config[DOMAIN][CONF_TOKEN] + + fgt = FortiOSAPI() + + try: + fgt.tokenlogin(host, token, verify_ssl) + except ConnectionError as ex: + _LOGGER.error("ConnectionError to FortiOS API: %s", ex) + return None + except Exception as ex: # pylint: disable=broad-except + _LOGGER.error("Failed to login to FortiOS API: %s", ex) + return None + + return FortiOSDeviceScanner(fgt) + + +class FortiOSDeviceScanner(DeviceScanner): + """This class queries a FortiOS unit for connected devices.""" + + def __init__(self, fgt) -> None: + """Initialize the scanner.""" + self._clients = {} + self._clients_json = {} + self._fgt = fgt + + def update(self): + """Update clients from the device.""" + clients_json = self._fgt.monitor('user/device/select', '') + self._clients_json = clients_json + + self._clients = [] + + if clients_json: + for client in clients_json['results']: + if client['last_seen'] < 180: + self._clients.append(client['mac'].upper()) + + def scan_devices(self): + """Scan for new devices and return a list with found device IDs.""" + self.update() + return self._clients + + def get_device_name(self, device): + """Return the name of the given device or None if we don't know.""" + _LOGGER.debug("Getting name of device %s", device) + + device = device.lower() + + data = self._clients_json + + if data == 0: + _LOGGER.error('No json results to get device names') + return None + + for client in data['results']: + if client['mac'] == device: + try: + name = client['host']['name'] + _LOGGER.debug("Getting device name=%s", name) + return name + except KeyError as kex: + _LOGGER.error("Name not found in client data: %s", kex) + return None + + return None diff --git a/homeassistant/components/fortios/manifest.json b/homeassistant/components/fortios/manifest.json new file mode 100644 index 00000000000..a63d4b292ad --- /dev/null +++ b/homeassistant/components/fortios/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "fortios", + "name": "Home Assistant Device Tracker to support FortiOS", + "documentation": "https://www.home-assistant.io/components/fortios/", + "requirements": [ + "fortiosapi==0.10.8" + ], + "dependencies": [], + "codeowners": ["@kimfrellsen"] +} diff --git a/requirements_all.txt b/requirements_all.txt index b66d1999a0d..148fc6ed97e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -493,6 +493,9 @@ flux_led==0.22 # homeassistant.components.foobot foobot_async==0.3.1 +# homeassistant.components.fortios +fortiosapi==0.10.8 + # homeassistant.components.free_mobile freesms==0.1.2