Make the network device tracking feature optional in AVM Fritz!Tools (#144149)

* make the network device tracking feature optional

* fix doc strings

* Apply suggestions from code review

Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>

---------

Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
This commit is contained in:
Michael 2025-05-03 21:04:59 +02:00 committed by GitHub
parent aea5760424
commit fb94f8ea18
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 71 additions and 17 deletions

View File

@ -15,6 +15,8 @@ from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.typing import ConfigType
from .const import (
CONF_FEATURE_DEVICE_TRACKING,
DEFAULT_CONF_FEATURE_DEVICE_TRACKING,
DEFAULT_SSL,
DOMAIN,
FRITZ_AUTH_EXCEPTIONS,
@ -38,6 +40,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def async_setup_entry(hass: HomeAssistant, entry: FritzConfigEntry) -> bool:
"""Set up fritzboxtools from config entry."""
_LOGGER.debug("Setting up FRITZ!Box Tools component")
avm_wrapper = AvmWrapper(
hass=hass,
config_entry=entry,
@ -46,6 +49,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: FritzConfigEntry) -> boo
username=entry.data[CONF_USERNAME],
password=entry.data[CONF_PASSWORD],
use_tls=entry.data.get(CONF_SSL, DEFAULT_SSL),
device_discovery_enabled=entry.options.get(
CONF_FEATURE_DEVICE_TRACKING, DEFAULT_CONF_FEATURE_DEVICE_TRACKING
),
)
try:
@ -62,6 +68,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: FritzConfigEntry) -> boo
raise ConfigEntryAuthFailed("Missing UPnP configuration")
await avm_wrapper.async_config_entry_first_refresh()
await avm_wrapper.async_trigger_cleanup()
entry.runtime_data = avm_wrapper

View File

@ -35,7 +35,9 @@ from homeassistant.helpers.service_info.ssdp import (
from homeassistant.helpers.typing import VolDictType
from .const import (
CONF_FEATURE_DEVICE_TRACKING,
CONF_OLD_DISCOVERY,
DEFAULT_CONF_FEATURE_DEVICE_TRACKING,
DEFAULT_CONF_OLD_DISCOVERY,
DEFAULT_HOST,
DEFAULT_HTTP_PORT,
@ -72,7 +74,8 @@ class FritzBoxToolsFlowHandler(ConfigFlow, domain=DOMAIN):
"""Initialize FRITZ!Box Tools flow."""
self._name: str = ""
self._password: str = ""
self._use_tls: bool = False
self._use_tls: bool = DEFAULT_SSL
self._feature_device_discovery: bool = DEFAULT_CONF_FEATURE_DEVICE_TRACKING
self._port: int | None = None
self._username: str = ""
self._model: str = ""
@ -141,6 +144,7 @@ class FritzBoxToolsFlowHandler(ConfigFlow, domain=DOMAIN):
options={
CONF_CONSIDER_HOME: DEFAULT_CONSIDER_HOME.total_seconds(),
CONF_OLD_DISCOVERY: DEFAULT_CONF_OLD_DISCOVERY,
CONF_FEATURE_DEVICE_TRACKING: self._feature_device_discovery,
},
)
@ -204,6 +208,7 @@ class FritzBoxToolsFlowHandler(ConfigFlow, domain=DOMAIN):
self._username = user_input[CONF_USERNAME]
self._password = user_input[CONF_PASSWORD]
self._use_tls = user_input[CONF_SSL]
self._feature_device_discovery = user_input[CONF_FEATURE_DEVICE_TRACKING]
self._port = self._determine_port(user_input)
error = await self.async_fritz_tools_init()
@ -234,6 +239,10 @@ class FritzBoxToolsFlowHandler(ConfigFlow, domain=DOMAIN):
vol.Required(CONF_USERNAME): str,
vol.Required(CONF_PASSWORD): str,
vol.Optional(CONF_SSL, default=DEFAULT_SSL): bool,
vol.Required(
CONF_FEATURE_DEVICE_TRACKING,
default=DEFAULT_CONF_FEATURE_DEVICE_TRACKING,
): bool,
}
),
errors=errors or {},
@ -250,6 +259,10 @@ class FritzBoxToolsFlowHandler(ConfigFlow, domain=DOMAIN):
vol.Required(CONF_USERNAME): str,
vol.Required(CONF_PASSWORD): str,
vol.Optional(CONF_SSL, default=DEFAULT_SSL): bool,
vol.Required(
CONF_FEATURE_DEVICE_TRACKING,
default=DEFAULT_CONF_FEATURE_DEVICE_TRACKING,
): bool,
}
),
description_placeholders={"name": self._name},
@ -405,7 +418,7 @@ class FritzBoxToolsOptionsFlowHandler(OptionsFlow):
"""Handle options flow."""
if user_input is not None:
return self.async_create_entry(title="", data=user_input)
return self.async_create_entry(data=user_input)
options = self.config_entry.options
data_schema = vol.Schema(
@ -420,6 +433,13 @@ class FritzBoxToolsOptionsFlowHandler(OptionsFlow):
CONF_OLD_DISCOVERY,
default=options.get(CONF_OLD_DISCOVERY, DEFAULT_CONF_OLD_DISCOVERY),
): bool,
vol.Optional(
CONF_FEATURE_DEVICE_TRACKING,
default=options.get(
CONF_FEATURE_DEVICE_TRACKING,
DEFAULT_CONF_FEATURE_DEVICE_TRACKING,
),
): bool,
}
)
return self.async_show_form(step_id="init", data_schema=data_schema)

View File

@ -40,6 +40,9 @@ PLATFORMS = [
CONF_OLD_DISCOVERY = "old_discovery"
DEFAULT_CONF_OLD_DISCOVERY = False
CONF_FEATURE_DEVICE_TRACKING = "feature_device_tracking"
DEFAULT_CONF_FEATURE_DEVICE_TRACKING = True
DSL_CONNECTION: Literal["dsl"] = "dsl"
DEFAULT_DEVICE_NAME = "Unknown device"

View File

@ -39,6 +39,7 @@ from homeassistant.util.hass_dict import HassKey
from .const import (
CONF_OLD_DISCOVERY,
DEFAULT_CONF_FEATURE_DEVICE_TRACKING,
DEFAULT_CONF_OLD_DISCOVERY,
DEFAULT_HOST,
DEFAULT_SSL,
@ -175,6 +176,7 @@ class FritzBoxTools(DataUpdateCoordinator[UpdateCoordinatorDataType]):
username: str = DEFAULT_USERNAME,
host: str = DEFAULT_HOST,
use_tls: bool = DEFAULT_SSL,
device_discovery_enabled: bool = DEFAULT_CONF_FEATURE_DEVICE_TRACKING,
) -> None:
"""Initialize FritzboxTools class."""
super().__init__(
@ -202,6 +204,7 @@ class FritzBoxTools(DataUpdateCoordinator[UpdateCoordinatorDataType]):
self.port = port
self.username = username
self.use_tls = use_tls
self.device_discovery_enabled = device_discovery_enabled
self.has_call_deflections: bool = False
self._model: str | None = None
self._current_firmware: str | None = None
@ -332,10 +335,15 @@ class FritzBoxTools(DataUpdateCoordinator[UpdateCoordinatorDataType]):
"entity_states": {},
}
try:
await self.async_scan_devices()
await self.async_update_device_info()
if self.device_discovery_enabled:
await self.async_scan_devices()
entity_data["entity_states"] = await self.hass.async_add_executor_job(
self._entity_states_update
)
if self.has_call_deflections:
entity_data[
"call_deflections"
@ -551,12 +559,8 @@ class FritzBoxTools(DataUpdateCoordinator[UpdateCoordinatorDataType]):
if new_device:
async_dispatcher_send(self.hass, self.signal_device_new)
async def async_scan_devices(self, now: datetime | None = None) -> None:
"""Scan for new devices and return a list of found device ids."""
if self.hass.is_stopping:
_ha_is_stopping("scan devices")
return
async def async_update_device_info(self, now: datetime | None = None) -> None:
"""Update own device information."""
_LOGGER.debug("Checking host info for FRITZ!Box device %s", self.host)
(
@ -565,6 +569,13 @@ class FritzBoxTools(DataUpdateCoordinator[UpdateCoordinatorDataType]):
self._release_url,
) = await self._async_update_device_info()
async def async_scan_devices(self, now: datetime | None = None) -> None:
"""Scan for new network devices."""
if self.hass.is_stopping:
_ha_is_stopping("scan devices")
return
_LOGGER.debug("Checking devices for FRITZ!Box device %s", self.host)
_default_consider_home = DEFAULT_CONSIDER_HOME.total_seconds()
if self._options:
@ -683,7 +694,10 @@ class FritzBoxTools(DataUpdateCoordinator[UpdateCoordinatorDataType]):
async def async_trigger_cleanup(self) -> None:
"""Trigger device trackers cleanup."""
device_hosts = await self._async_update_hosts_info()
_LOGGER.debug("Device tracker cleanup triggered")
device_hosts = {self.mac: Device(True, "", "", "", "", None)}
if self.device_discovery_enabled:
device_hosts = await self._async_update_hosts_info()
entity_reg: er.EntityRegistry = er.async_get(self.hass)
config_entry = self.config_entry

View File

@ -4,7 +4,9 @@
"data_description_port": "Leave empty to use the default port.",
"data_description_username": "Username for the FRITZ!Box.",
"data_description_password": "Password for the FRITZ!Box.",
"data_description_ssl": "Use SSL to connect to the FRITZ!Box."
"data_description_ssl": "Use SSL to connect to the FRITZ!Box.",
"data_description_feature_device_tracking": "Enable or disable the network device tracking feature.",
"data_feature_device_tracking": "Enable network device tracking"
},
"config": {
"flow_title": "{name}",
@ -15,12 +17,14 @@
"data": {
"username": "[%key:common::config_flow::data::username%]",
"password": "[%key:common::config_flow::data::password%]",
"ssl": "[%key:common::config_flow::data::ssl%]"
"ssl": "[%key:common::config_flow::data::ssl%]",
"feature_device_tracking": "[%key:component::fritz::common::data_feature_device_tracking%]"
},
"data_description": {
"username": "[%key:component::fritz::common::data_description_username%]",
"password": "[%key:component::fritz::common::data_description_password%]",
"ssl": "[%key:component::fritz::common::data_description_ssl%]"
"ssl": "[%key:component::fritz::common::data_description_ssl%]",
"feature_device_tracking": "[%key:component::fritz::common::data_description_feature_device_tracking%]"
}
},
"reauth_confirm": {
@ -57,14 +61,16 @@
"port": "[%key:common::config_flow::data::port%]",
"username": "[%key:common::config_flow::data::username%]",
"password": "[%key:common::config_flow::data::password%]",
"ssl": "[%key:common::config_flow::data::ssl%]"
"ssl": "[%key:common::config_flow::data::ssl%]",
"feature_device_tracking": "[%key:component::fritz::common::data_feature_device_tracking%]"
},
"data_description": {
"host": "[%key:component::fritz::common::data_description_host%]",
"port": "[%key:component::fritz::common::data_description_port%]",
"username": "[%key:component::fritz::common::data_description_username%]",
"password": "[%key:component::fritz::common::data_description_password%]",
"ssl": "[%key:component::fritz::common::data_description_ssl%]"
"ssl": "[%key:component::fritz::common::data_description_ssl%]",
"feature_device_tracking": "[%key:component::fritz::common::data_description_feature_device_tracking%]"
}
}
},
@ -89,11 +95,13 @@
"init": {
"data": {
"consider_home": "Seconds to consider a device at 'home'",
"old_discovery": "Enable old discovery method"
"old_discovery": "Enable old discovery method",
"feature_device_tracking": "[%key:component::fritz::common::data_feature_device_tracking%]"
},
"data_description": {
"consider_home": "Time in seconds to consider a device at home. Default is 180 seconds.",
"old_discovery": "Enable old discovery method. This is needed for some scenarios."
"old_discovery": "Enable old discovery method. This is needed for some scenarios.",
"feature_device_tracking": "[%key:component::fritz::common::data_description_feature_device_tracking%]"
}
}
}

View File

@ -16,6 +16,7 @@ from homeassistant.components.device_tracker import (
DEFAULT_CONSIDER_HOME,
)
from homeassistant.components.fritz.const import (
CONF_FEATURE_DEVICE_TRACKING,
CONF_OLD_DISCOVERY,
DOMAIN,
ERROR_AUTH_INVALID,
@ -744,6 +745,7 @@ async def test_options_flow(hass: HomeAssistant) -> None:
assert result["data"] == {
CONF_OLD_DISCOVERY: False,
CONF_CONSIDER_HOME: 37,
CONF_FEATURE_DEVICE_TRACKING: True,
}