Home Assistant Unofficial Reference 2024.12.1
device_tracker.py
Go to the documentation of this file.
1 """Support to use FortiOS device like FortiGate as device tracker.
2 
3 This component is part of the device_tracker platform.
4 """
5 
6 from __future__ import annotations
7 
8 import logging
9 from typing import Any
10 
11 from awesomeversion import AwesomeVersion
12 from fortiosapi import FortiOSAPI
13 import voluptuous as vol
14 
16  DOMAIN as DEVICE_TRACKER_DOMAIN,
17  PLATFORM_SCHEMA as DEVICE_TRACKER_PLATFORM_SCHEMA,
18  DeviceScanner,
19 )
20 from homeassistant.const import CONF_HOST, CONF_TOKEN, CONF_VERIFY_SSL
21 from homeassistant.core import HomeAssistant
23 from homeassistant.helpers.typing import ConfigType
24 
25 _LOGGER = logging.getLogger(__name__)
26 DEFAULT_VERIFY_SSL = False
27 
28 
29 PLATFORM_SCHEMA = DEVICE_TRACKER_PLATFORM_SCHEMA.extend(
30  {
31  vol.Required(CONF_HOST): cv.string,
32  vol.Required(CONF_TOKEN): cv.string,
33  vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean,
34  }
35 )
36 
37 
38 def get_scanner(hass: HomeAssistant, config: ConfigType) -> FortiOSDeviceScanner | None:
39  """Validate the configuration and return a FortiOSDeviceScanner."""
40  config = config[DEVICE_TRACKER_DOMAIN]
41 
42  host = config[CONF_HOST]
43  verify_ssl = config[CONF_VERIFY_SSL]
44  token = config[CONF_TOKEN]
45 
46  fgt = FortiOSAPI()
47 
48  try:
49  fgt.tokenlogin(host, token, verify_ssl, None, 12, "root")
50  except ConnectionError as ex:
51  _LOGGER.error("ConnectionError to FortiOS API: %s", ex)
52  return None
53  except Exception as ex: # noqa: BLE001
54  _LOGGER.error("Failed to login to FortiOS API: %s", ex)
55  return None
56 
57  status_json = fgt.monitor("system/status", "")
58 
59  current_version = AwesomeVersion(status_json["version"])
60  minimum_version = AwesomeVersion("6.4.3")
61  if current_version < minimum_version:
62  _LOGGER.error(
63  "Unsupported FortiOS version: %s. Version %s and newer are supported",
64  current_version,
65  minimum_version,
66  )
67  return None
68 
69  return FortiOSDeviceScanner(fgt)
70 
71 
72 class FortiOSDeviceScanner(DeviceScanner):
73  """Class which queries a FortiOS unit for connected devices."""
74 
75  def __init__(self, fgt) -> None:
76  """Initialize the scanner."""
77  self._clients_clients: list[str] = []
78  self._clients_json_clients_json: dict[str, Any] = {}
79  self._fgt_fgt = fgt
80 
81  def update(self):
82  """Update clients from the device."""
83  clients_json = self._fgt_fgt.monitor(
84  "user/device/query",
85  "",
86  parameters={"filter": "format=master_mac|hostname|is_online"},
87  )
88 
89  self._clients_json_clients_json = clients_json
90 
91  self._clients_clients = []
92 
93  if clients_json:
94  try:
95  for client in clients_json["results"]:
96  if (
97  "is_online" in client
98  and "master_mac" in client
99  and client["is_online"]
100  ):
101  self._clients_clients.append(client["master_mac"].upper())
102  except KeyError as kex:
103  _LOGGER.error("Key not found in clients: %s", kex)
104 
105  def scan_devices(self):
106  """Scan for new devices and return a list with found device IDs."""
107  self.updateupdate()
108  return self._clients_clients
109 
110  def get_device_name(self, device):
111  """Return the name of the given device or None if we don't know."""
112  _LOGGER.debug("Getting name of device %s", device)
113 
114  device = device.lower()
115 
116  if (data := self._clients_json_clients_json) == 0:
117  _LOGGER.error("No json results to get device names")
118  return None
119 
120  for client in data["results"]:
121  if "master_mac" in client and client["master_mac"] == device:
122  if "hostname" in client:
123  name = client["hostname"]
124  else:
125  name = client["master_mac"].replace(":", "_")
126  return name
127  return None
FortiOSDeviceScanner|None get_scanner(HomeAssistant hass, ConfigType config)