mirror of
https://github.com/home-assistant/core.git
synced 2025-12-20 02:48:57 +00:00
Add strict typing, shared constants, and fix OPNsense name casing (#151599)
This commit is contained in:
@@ -383,6 +383,7 @@ homeassistant.components.openai_conversation.*
|
|||||||
homeassistant.components.openexchangerates.*
|
homeassistant.components.openexchangerates.*
|
||||||
homeassistant.components.opensky.*
|
homeassistant.components.opensky.*
|
||||||
homeassistant.components.openuv.*
|
homeassistant.components.openuv.*
|
||||||
|
homeassistant.components.opnsense.*
|
||||||
homeassistant.components.opower.*
|
homeassistant.components.opower.*
|
||||||
homeassistant.components.oralb.*
|
homeassistant.components.oralb.*
|
||||||
homeassistant.components.otbr.*
|
homeassistant.components.otbr.*
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""Support for OPNSense Routers."""
|
"""Support for OPNsense Routers."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@@ -12,15 +12,16 @@ from homeassistant.helpers import config_validation as cv
|
|||||||
from homeassistant.helpers.discovery import load_platform
|
from homeassistant.helpers.discovery import load_platform
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
|
||||||
|
from .const import (
|
||||||
|
CONF_API_SECRET,
|
||||||
|
CONF_INTERFACE_CLIENT,
|
||||||
|
CONF_TRACKER_INTERFACES,
|
||||||
|
DOMAIN,
|
||||||
|
OPNSENSE_DATA,
|
||||||
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
CONF_API_SECRET = "api_secret"
|
|
||||||
CONF_TRACKER_INTERFACE = "tracker_interfaces"
|
|
||||||
|
|
||||||
DOMAIN = "opnsense"
|
|
||||||
|
|
||||||
OPNSENSE_DATA = DOMAIN
|
|
||||||
|
|
||||||
CONFIG_SCHEMA = vol.Schema(
|
CONFIG_SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
DOMAIN: vol.Schema(
|
DOMAIN: vol.Schema(
|
||||||
@@ -29,7 +30,7 @@ CONFIG_SCHEMA = vol.Schema(
|
|||||||
vol.Required(CONF_API_KEY): cv.string,
|
vol.Required(CONF_API_KEY): cv.string,
|
||||||
vol.Required(CONF_API_SECRET): cv.string,
|
vol.Required(CONF_API_SECRET): cv.string,
|
||||||
vol.Optional(CONF_VERIFY_SSL, default=False): cv.boolean,
|
vol.Optional(CONF_VERIFY_SSL, default=False): cv.boolean,
|
||||||
vol.Optional(CONF_TRACKER_INTERFACE, default=[]): vol.All(
|
vol.Optional(CONF_TRACKER_INTERFACES, default=[]): vol.All(
|
||||||
cv.ensure_list, [cv.string]
|
cv.ensure_list, [cv.string]
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@@ -47,7 +48,7 @@ def setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||||||
api_key = conf[CONF_API_KEY]
|
api_key = conf[CONF_API_KEY]
|
||||||
api_secret = conf[CONF_API_SECRET]
|
api_secret = conf[CONF_API_SECRET]
|
||||||
verify_ssl = conf[CONF_VERIFY_SSL]
|
verify_ssl = conf[CONF_VERIFY_SSL]
|
||||||
tracker_interfaces = conf[CONF_TRACKER_INTERFACE]
|
tracker_interfaces = conf[CONF_TRACKER_INTERFACES]
|
||||||
|
|
||||||
interfaces_client = diagnostics.InterfaceClient(
|
interfaces_client = diagnostics.InterfaceClient(
|
||||||
api_key, api_secret, url, verify_ssl, timeout=20
|
api_key, api_secret, url, verify_ssl, timeout=20
|
||||||
@@ -72,8 +73,8 @@ def setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
hass.data[OPNSENSE_DATA] = {
|
hass.data[OPNSENSE_DATA] = {
|
||||||
"interfaces": interfaces_client,
|
CONF_INTERFACE_CLIENT: interfaces_client,
|
||||||
CONF_TRACKER_INTERFACE: tracker_interfaces,
|
CONF_TRACKER_INTERFACES: tracker_interfaces,
|
||||||
}
|
}
|
||||||
|
|
||||||
load_platform(hass, Platform.DEVICE_TRACKER, DOMAIN, tracker_interfaces, config)
|
load_platform(hass, Platform.DEVICE_TRACKER, DOMAIN, tracker_interfaces, config)
|
||||||
|
|||||||
8
homeassistant/components/opnsense/const.py
Normal file
8
homeassistant/components/opnsense/const.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
"""Constants for OPNsense component."""
|
||||||
|
|
||||||
|
DOMAIN = "opnsense"
|
||||||
|
OPNSENSE_DATA = DOMAIN
|
||||||
|
|
||||||
|
CONF_API_SECRET = "api_secret"
|
||||||
|
CONF_INTERFACE_CLIENT = "interface_client"
|
||||||
|
CONF_TRACKER_INTERFACES = "tracker_interfaces"
|
||||||
@@ -1,34 +1,41 @@
|
|||||||
"""Device tracker support for OPNSense routers."""
|
"""Device tracker support for OPNsense routers."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from typing import Any, NewType
|
||||||
|
|
||||||
|
from pyopnsense import diagnostics
|
||||||
|
|
||||||
from homeassistant.components.device_tracker import DeviceScanner
|
from homeassistant.components.device_tracker import DeviceScanner
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
|
||||||
from . import CONF_TRACKER_INTERFACE, OPNSENSE_DATA
|
from .const import CONF_INTERFACE_CLIENT, CONF_TRACKER_INTERFACES, OPNSENSE_DATA
|
||||||
|
|
||||||
|
DeviceDetails = NewType("DeviceDetails", dict[str, Any])
|
||||||
|
DeviceDetailsByMAC = NewType("DeviceDetailsByMAC", dict[str, DeviceDetails])
|
||||||
|
|
||||||
|
|
||||||
async def async_get_scanner(
|
async def async_get_scanner(
|
||||||
hass: HomeAssistant, config: ConfigType
|
hass: HomeAssistant, config: ConfigType
|
||||||
) -> OPNSenseDeviceScanner:
|
) -> DeviceScanner | None:
|
||||||
"""Configure the OPNSense device_tracker."""
|
"""Configure the OPNsense device_tracker."""
|
||||||
interface_client = hass.data[OPNSENSE_DATA]["interfaces"]
|
return OPNsenseDeviceScanner(
|
||||||
return OPNSenseDeviceScanner(
|
hass.data[OPNSENSE_DATA][CONF_INTERFACE_CLIENT],
|
||||||
interface_client, hass.data[OPNSENSE_DATA][CONF_TRACKER_INTERFACE]
|
hass.data[OPNSENSE_DATA][CONF_TRACKER_INTERFACES],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class OPNSenseDeviceScanner(DeviceScanner):
|
class OPNsenseDeviceScanner(DeviceScanner):
|
||||||
"""Class which queries a router running OPNsense."""
|
"""This class queries a router running OPNsense."""
|
||||||
|
|
||||||
def __init__(self, client, interfaces):
|
def __init__(
|
||||||
|
self, client: diagnostics.InterfaceClient, interfaces: list[str]
|
||||||
|
) -> None:
|
||||||
"""Initialize the scanner."""
|
"""Initialize the scanner."""
|
||||||
self.last_results = {}
|
self.last_results: dict[str, Any] = {}
|
||||||
self.client = client
|
self.client = client
|
||||||
self.interfaces = interfaces
|
self.interfaces = interfaces
|
||||||
|
|
||||||
def _get_mac_addrs(self, devices):
|
def _get_mac_addrs(self, devices: list[DeviceDetails]) -> DeviceDetailsByMAC | dict:
|
||||||
"""Create dict with mac address keys from list of devices."""
|
"""Create dict with mac address keys from list of devices."""
|
||||||
out_devices = {}
|
out_devices = {}
|
||||||
for device in devices:
|
for device in devices:
|
||||||
@@ -36,30 +43,31 @@ class OPNSenseDeviceScanner(DeviceScanner):
|
|||||||
out_devices[device["mac"]] = device
|
out_devices[device["mac"]] = device
|
||||||
return out_devices
|
return out_devices
|
||||||
|
|
||||||
def scan_devices(self):
|
def scan_devices(self) -> list[str]:
|
||||||
"""Scan for new devices and return a list with found device IDs."""
|
"""Scan for new devices and return a list with found device IDs."""
|
||||||
self.update_info()
|
self.update_info()
|
||||||
return list(self.last_results)
|
return list(self.last_results)
|
||||||
|
|
||||||
def get_device_name(self, device):
|
def get_device_name(self, device: str) -> str | None:
|
||||||
"""Return the name of the given device or None if we don't know."""
|
"""Return the name of the given device or None if we don't know."""
|
||||||
if device not in self.last_results:
|
if device not in self.last_results:
|
||||||
return None
|
return None
|
||||||
return self.last_results[device].get("hostname") or None
|
return self.last_results[device].get("hostname") or None
|
||||||
|
|
||||||
def update_info(self):
|
def update_info(self) -> bool:
|
||||||
"""Ensure the information from the OPNSense router is up to date.
|
"""Ensure the information from the OPNsense router is up to date.
|
||||||
|
|
||||||
Return boolean if scanning successful.
|
Return boolean if scanning successful.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
devices = self.client.get_arp()
|
devices = self.client.get_arp()
|
||||||
self.last_results = self._get_mac_addrs(devices)
|
self.last_results = self._get_mac_addrs(devices)
|
||||||
|
return True
|
||||||
|
|
||||||
def get_extra_attributes(self, device):
|
def get_extra_attributes(self, device: str) -> dict[Any, Any]:
|
||||||
"""Return the extra attrs of the given device."""
|
"""Return the extra attrs of the given device."""
|
||||||
if device not in self.last_results:
|
if device not in self.last_results:
|
||||||
return None
|
return {}
|
||||||
if not (mfg := self.last_results[device].get("manufacturer")):
|
mfg = self.last_results[device].get("manufacturer")
|
||||||
|
if not mfg:
|
||||||
return {}
|
return {}
|
||||||
return {"manufacturer": mfg}
|
return {"manufacturer": mfg}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"domain": "opnsense",
|
"domain": "opnsense",
|
||||||
"name": "OPNSense",
|
"name": "OPNsense",
|
||||||
"codeowners": ["@mtreinish"],
|
"codeowners": ["@mtreinish"],
|
||||||
"documentation": "https://www.home-assistant.io/integrations/opnsense",
|
"documentation": "https://www.home-assistant.io/integrations/opnsense",
|
||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
|
|||||||
@@ -4736,7 +4736,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"opnsense": {
|
"opnsense": {
|
||||||
"name": "OPNSense",
|
"name": "OPNsense",
|
||||||
"integration_type": "hub",
|
"integration_type": "hub",
|
||||||
"config_flow": false,
|
"config_flow": false,
|
||||||
"iot_class": "local_polling"
|
"iot_class": "local_polling"
|
||||||
|
|||||||
10
mypy.ini
generated
10
mypy.ini
generated
@@ -3586,6 +3586,16 @@ disallow_untyped_defs = true
|
|||||||
warn_return_any = true
|
warn_return_any = true
|
||||||
warn_unreachable = true
|
warn_unreachable = true
|
||||||
|
|
||||||
|
[mypy-homeassistant.components.opnsense.*]
|
||||||
|
check_untyped_defs = true
|
||||||
|
disallow_incomplete_defs = true
|
||||||
|
disallow_subclassing_any = true
|
||||||
|
disallow_untyped_calls = true
|
||||||
|
disallow_untyped_decorators = true
|
||||||
|
disallow_untyped_defs = true
|
||||||
|
warn_return_any = true
|
||||||
|
warn_unreachable = true
|
||||||
|
|
||||||
[mypy-homeassistant.components.opower.*]
|
[mypy-homeassistant.components.opower.*]
|
||||||
check_untyped_defs = true
|
check_untyped_defs = true
|
||||||
disallow_incomplete_defs = true
|
disallow_incomplete_defs = true
|
||||||
|
|||||||
Reference in New Issue
Block a user