Skip to content

Commit

Permalink
Add Fortigate integration (home-assistant#24908)
Browse files Browse the repository at this point in the history
* Add Fortigate integration

* added feedback changes

* removed the only case

* fixed a description

* removed the CONFIG_PLATFORM

* deleted README

* added return from setup

* added return from setup

* fixed reviews

* Link updated

* Rename var and a couple of other minor changes

* Typos
  • Loading branch information
kifeo authored and fabaff committed Jul 16, 2019
1 parent f9ae6f6 commit 3d3dd05
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 0 deletions.
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ omit =
homeassistant/components/folder/sensor.py
homeassistant/components/folder_watcher/*
homeassistant/components/foobot/sensor.py
homeassistant/components/fortigate/*
homeassistant/components/foscam/camera.py
homeassistant/components/foursquare/*
homeassistant/components/free_mobile/notify.py
Expand Down
1 change: 1 addition & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ homeassistant/components/fitbit/* @robbiet480
homeassistant/components/fixer/* @fabaff
homeassistant/components/flock/* @fabaff
homeassistant/components/flunearyou/* @bachya
homeassistant/components/fortigate/* @kifeo
homeassistant/components/foursquare/* @robbiet480
homeassistant/components/freebox/* @snoof85
homeassistant/components/fronius/* @nielstron
Expand Down
71 changes: 71 additions & 0 deletions homeassistant/components/fortigate/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""Fortigate integration."""
import logging

import voluptuous as vol

from homeassistant.const import (
CONF_DEVICES, CONF_HOST, CONF_API_KEY, CONF_USERNAME,
EVENT_HOMEASSISTANT_STOP)
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.discovery import async_load_platform

_LOGGER = logging.getLogger(__name__)

DOMAIN = 'fortigate'

DATA_FGT = DOMAIN

CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_API_KEY): cv.string,
vol.Optional(CONF_DEVICES, default=[]):
vol.All(cv.ensure_list, [cv.string]),
})
}, extra=vol.ALLOW_EXTRA)


async def async_setup(hass, config):
"""Start the Fortigate component."""
conf = config[DOMAIN]

host = conf[CONF_HOST]
user = conf[CONF_USERNAME]
api_key = conf[CONF_API_KEY]
devices = conf[CONF_DEVICES]

is_success = await async_setup_fortigate(
hass, config, host, user, api_key, devices
)

return is_success


async def async_setup_fortigate(hass, config, host, user, api_key, devices):
"""Start up the Fortigate component platforms."""
from pyFGT.fortigate import FGTConnectionError, FortiGate

fgt = FortiGate(host, user, apikey=api_key, disable_request_warnings=True)

try:
fgt.login()
except FGTConnectionError:
_LOGGER.error("Failed to connect to Fortigate")
return False

hass.data[DATA_FGT] = {
'fgt': fgt,
'devices': devices
}

hass.async_create_task(async_load_platform(
hass, 'device_tracker', DOMAIN, {}, config))

async def close_fgt(event):
"""Close Fortigate connection on HA Stop."""
fgt.logout()

hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, close_fgt)

return True
93 changes: 93 additions & 0 deletions homeassistant/components/fortigate/device_tracker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"""Device tracker for Fortigate firewalls."""
from collections import namedtuple
import logging

from homeassistant.components.device_tracker import DeviceScanner

from . import DATA_FGT

_LOGGER = logging.getLogger(__name__)

DETECTED_DEVICES = "/monitor/user/detected-device"


async def async_get_scanner(hass, config):
"""Validate the configuration and return a Fortigate scanner."""
scanner = FortigateDeviceScanner(hass.data[DATA_FGT])
await scanner.async_connect()
return scanner if scanner.success_init else None


Device = namedtuple('Device', ['hostname', 'mac'])


def _build_device(device_dict):
"""Return a Device from data."""
return Device(
device_dict['hostname'],
device_dict['mac'])


class FortigateDeviceScanner(DeviceScanner):
"""Query the Fortigate firewall."""

def __init__(self, hass_data):
"""Initialize the scanner."""
self.last_results = {}
self.success_init = False
self.connection = hass_data['fgt']
self.devices = hass_data['devices']

def get_results(self):
"""Get the results from the Fortigate."""
results = self.connection.get(
DETECTED_DEVICES, "vdom=root")[1]['results']

ret = []
for result in results:
if 'hostname' not in result:
continue

ret.append(result)

return ret

async def async_connect(self):
"""Initialize connection to the router."""
# Test if the firewall is accessible
data = self.get_results()
self.success_init = data is not None

async def async_scan_devices(self):
"""Scan for new devices and return a list with found device MACs."""
await self.async_update_info()
return [device.mac for device in self.last_results]

async def get_device_name(self, device):
"""Return the name of the given device or None if we don't know."""
name = next((
result.hostname for result in self.last_results
if result.mac == device), None)
return name

async def async_update_info(self):
"""Ensure the information from the Fortigate firewall is up to date."""
_LOGGER.debug("Checking devices")

hosts = self.get_results()

all_results = [_build_device(device) for device in hosts
if device['is_online']]

# If the 'devices' configuration field is filled
if self.devices is not None:
last_results = [
device for device in all_results
if device.hostname in self.devices
]
_LOGGER.debug(last_results)
# If the 'devices' configuration field is not filled
else:
last_results = all_results

self.last_results = last_results
12 changes: 12 additions & 0 deletions homeassistant/components/fortigate/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"domain": "fortigate",
"name": "Fortigate",
"documentation": "https://www.home-assistant.io/components/fortigate",
"dependencies": [],
"codeowners": [
"@kifeo"
],
"requirements": [
"pyfgt==0.5.1"
]
}
3 changes: 3 additions & 0 deletions requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,9 @@ pyephember==0.2.0
# homeassistant.components.everlights
pyeverlights==0.1.0

# homeassistant.components.fortigate
pyfgt==0.5.1

# homeassistant.components.fido
pyfido==2.1.1

Expand Down

0 comments on commit 3d3dd05

Please sign in to comment.