mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 10:47:10 +00:00
Fritz clean device_tracker service (#56535)
This commit is contained in:
parent
19eba5a3a0
commit
f8af44cac2
@ -17,15 +17,27 @@ from fritzconnection.core.exceptions import (
|
|||||||
from fritzconnection.lib.fritzhosts import FritzHosts
|
from fritzconnection.lib.fritzhosts import FritzHosts
|
||||||
from fritzconnection.lib.fritzstatus import FritzStatus
|
from fritzconnection.lib.fritzstatus import FritzStatus
|
||||||
|
|
||||||
|
from homeassistant.components.device_tracker import DOMAIN as DEVICE_TRACKER_DOMAIN
|
||||||
from homeassistant.components.device_tracker.const import (
|
from homeassistant.components.device_tracker.const import (
|
||||||
CONF_CONSIDER_HOME,
|
CONF_CONSIDER_HOME,
|
||||||
DEFAULT_CONSIDER_HOME,
|
DEFAULT_CONSIDER_HOME,
|
||||||
)
|
)
|
||||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
|
from homeassistant.components.switch import DOMAIN as DEVICE_SWITCH_DOMAIN
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, ServiceCall, callback
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
|
from homeassistant.helpers.device_registry import (
|
||||||
|
CONNECTION_NETWORK_MAC,
|
||||||
|
async_entries_for_config_entry,
|
||||||
|
async_get,
|
||||||
|
)
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect, dispatcher_send
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect, dispatcher_send
|
||||||
from homeassistant.helpers.entity import DeviceInfo, Entity
|
from homeassistant.helpers.entity import DeviceInfo, Entity
|
||||||
|
from homeassistant.helpers.entity_registry import (
|
||||||
|
EntityRegistry,
|
||||||
|
RegistryEntry,
|
||||||
|
async_entries_for_device,
|
||||||
|
)
|
||||||
from homeassistant.helpers.event import async_track_time_interval
|
from homeassistant.helpers.event import async_track_time_interval
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
@ -35,6 +47,7 @@ from .const import (
|
|||||||
DEFAULT_PORT,
|
DEFAULT_PORT,
|
||||||
DEFAULT_USERNAME,
|
DEFAULT_USERNAME,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
SERVICE_CLEANUP,
|
||||||
SERVICE_REBOOT,
|
SERVICE_REBOOT,
|
||||||
SERVICE_RECONNECT,
|
SERVICE_RECONNECT,
|
||||||
TRACKER_SCAN_INTERVAL,
|
TRACKER_SCAN_INTERVAL,
|
||||||
@ -70,6 +83,13 @@ def device_filter_out_from_trackers(
|
|||||||
return bool(reason)
|
return bool(reason)
|
||||||
|
|
||||||
|
|
||||||
|
def _cleanup_entity_filter(device: RegistryEntry) -> bool:
|
||||||
|
"""Filter only relevant entities."""
|
||||||
|
return device.domain == DEVICE_TRACKER_DOMAIN or (
|
||||||
|
device.domain == DEVICE_SWITCH_DOMAIN and "_internet_access" in device.entity_id
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ClassSetupMissing(Exception):
|
class ClassSetupMissing(Exception):
|
||||||
"""Raised when a Class func is called before setup."""
|
"""Raised when a Class func is called before setup."""
|
||||||
|
|
||||||
@ -281,29 +301,83 @@ class FritzBoxTools:
|
|||||||
_LOGGER.debug("Checking host info for FRITZ!Box router %s", self.host)
|
_LOGGER.debug("Checking host info for FRITZ!Box router %s", self.host)
|
||||||
self._update_available, self._latest_firmware = self._update_device_info()
|
self._update_available, self._latest_firmware = self._update_device_info()
|
||||||
|
|
||||||
async def service_fritzbox(self, service: str) -> None:
|
async def service_fritzbox(
|
||||||
|
self, service_call: ServiceCall, config_entry: ConfigEntry
|
||||||
|
) -> None:
|
||||||
"""Define FRITZ!Box services."""
|
"""Define FRITZ!Box services."""
|
||||||
_LOGGER.debug("FRITZ!Box router: %s", service)
|
_LOGGER.debug("FRITZ!Box router: %s", service_call.service)
|
||||||
|
|
||||||
if not self.connection:
|
if not self.connection:
|
||||||
raise HomeAssistantError("Unable to establish a connection")
|
raise HomeAssistantError("Unable to establish a connection")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if service == SERVICE_REBOOT:
|
if service_call.service == SERVICE_REBOOT:
|
||||||
await self.hass.async_add_executor_job(
|
await self.hass.async_add_executor_job(
|
||||||
self.connection.call_action, "DeviceConfig1", "Reboot"
|
self.connection.call_action, "DeviceConfig1", "Reboot"
|
||||||
)
|
)
|
||||||
elif service == SERVICE_RECONNECT:
|
return
|
||||||
|
|
||||||
|
if service_call.service == SERVICE_RECONNECT:
|
||||||
await self.hass.async_add_executor_job(
|
await self.hass.async_add_executor_job(
|
||||||
self.connection.call_action,
|
self.connection.call_action,
|
||||||
"WANIPConn1",
|
"WANIPConn1",
|
||||||
"ForceTermination",
|
"ForceTermination",
|
||||||
)
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
if service_call.service == SERVICE_CLEANUP:
|
||||||
|
device_hosts_list: list = await self.hass.async_add_executor_job(
|
||||||
|
self.fritz_hosts.get_hosts_info
|
||||||
|
)
|
||||||
|
|
||||||
except (FritzServiceError, FritzActionError) as ex:
|
except (FritzServiceError, FritzActionError) as ex:
|
||||||
raise HomeAssistantError("Service or parameter unknown") from ex
|
raise HomeAssistantError("Service or parameter unknown") from ex
|
||||||
except FritzConnectionException as ex:
|
except FritzConnectionException as ex:
|
||||||
raise HomeAssistantError("Service not supported") from ex
|
raise HomeAssistantError("Service not supported") from ex
|
||||||
|
|
||||||
|
entity_reg: EntityRegistry = (
|
||||||
|
await self.hass.helpers.entity_registry.async_get_registry()
|
||||||
|
)
|
||||||
|
|
||||||
|
ha_entity_reg_list: list[
|
||||||
|
RegistryEntry
|
||||||
|
] = self.hass.helpers.entity_registry.async_entries_for_config_entry(
|
||||||
|
entity_reg, config_entry.entry_id
|
||||||
|
)
|
||||||
|
entities_removed: bool = False
|
||||||
|
|
||||||
|
device_hosts_macs = {device["mac"] for device in device_hosts_list}
|
||||||
|
|
||||||
|
for entry in ha_entity_reg_list:
|
||||||
|
if (
|
||||||
|
not _cleanup_entity_filter(entry)
|
||||||
|
or entry.unique_id.split("_")[0] in device_hosts_macs
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
_LOGGER.info("Removing entity: %s", entry.name or entry.original_name)
|
||||||
|
entity_reg.async_remove(entry.entity_id)
|
||||||
|
entities_removed = True
|
||||||
|
|
||||||
|
if entities_removed:
|
||||||
|
self._async_remove_empty_devices(entity_reg, config_entry)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _async_remove_empty_devices(
|
||||||
|
self, entity_reg: EntityRegistry, config_entry: ConfigEntry
|
||||||
|
) -> None:
|
||||||
|
"""Remove devices with no entities."""
|
||||||
|
|
||||||
|
device_reg = async_get(self.hass)
|
||||||
|
device_list = async_entries_for_config_entry(device_reg, config_entry.entry_id)
|
||||||
|
for device_entry in device_list:
|
||||||
|
if async_entries_for_device(
|
||||||
|
entity_reg,
|
||||||
|
device_entry.id,
|
||||||
|
include_disabled_entities=True,
|
||||||
|
):
|
||||||
|
_LOGGER.info("Removing device: %s", device_entry.name)
|
||||||
|
device_reg.async_remove_device(device_entry.id)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FritzData:
|
class FritzData:
|
||||||
|
@ -22,6 +22,7 @@ ERROR_UNKNOWN = "unknown_error"
|
|||||||
FRITZ_SERVICES = "fritz_services"
|
FRITZ_SERVICES = "fritz_services"
|
||||||
SERVICE_REBOOT = "reboot"
|
SERVICE_REBOOT = "reboot"
|
||||||
SERVICE_RECONNECT = "reconnect"
|
SERVICE_RECONNECT = "reconnect"
|
||||||
|
SERVICE_CLEANUP = "cleanup"
|
||||||
|
|
||||||
SWITCH_TYPE_DEFLECTION = "CallDeflection"
|
SWITCH_TYPE_DEFLECTION = "CallDeflection"
|
||||||
SWITCH_TYPE_PORTFORWARD = "PortForward"
|
SWITCH_TYPE_PORTFORWARD = "PortForward"
|
||||||
|
@ -5,15 +5,25 @@ from homeassistant.core import HomeAssistant, ServiceCall
|
|||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers.service import async_extract_config_entry_ids
|
from homeassistant.helpers.service import async_extract_config_entry_ids
|
||||||
|
|
||||||
from .const import DOMAIN, FRITZ_SERVICES, SERVICE_REBOOT, SERVICE_RECONNECT
|
from .common import FritzBoxTools
|
||||||
|
from .const import (
|
||||||
|
DOMAIN,
|
||||||
|
FRITZ_SERVICES,
|
||||||
|
SERVICE_CLEANUP,
|
||||||
|
SERVICE_REBOOT,
|
||||||
|
SERVICE_RECONNECT,
|
||||||
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
SERVICE_LIST = [SERVICE_CLEANUP, SERVICE_REBOOT, SERVICE_RECONNECT]
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_services(hass: HomeAssistant) -> None:
|
async def async_setup_services(hass: HomeAssistant) -> None:
|
||||||
"""Set up services for Fritz integration."""
|
"""Set up services for Fritz integration."""
|
||||||
|
|
||||||
for service in (SERVICE_REBOOT, SERVICE_RECONNECT):
|
for service in SERVICE_LIST:
|
||||||
if hass.services.has_service(DOMAIN, service):
|
if hass.services.has_service(DOMAIN, service):
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -29,12 +39,18 @@ async def async_setup_services(hass: HomeAssistant) -> None:
|
|||||||
f"Failed to call service '{service_call.service}'. Config entry for target not found"
|
f"Failed to call service '{service_call.service}'. Config entry for target not found"
|
||||||
)
|
)
|
||||||
|
|
||||||
for entry in fritzbox_entry_ids:
|
for entry_id in fritzbox_entry_ids:
|
||||||
_LOGGER.debug("Executing service %s", service_call.service)
|
_LOGGER.debug("Executing service %s", service_call.service)
|
||||||
fritz_tools = hass.data[DOMAIN][entry]
|
fritz_tools: FritzBoxTools = hass.data[DOMAIN][entry_id]
|
||||||
await fritz_tools.service_fritzbox(service_call.service)
|
if config_entry := hass.config_entries.async_get_entry(entry_id):
|
||||||
|
await fritz_tools.service_fritzbox(service_call, config_entry)
|
||||||
|
else:
|
||||||
|
_LOGGER.error(
|
||||||
|
"Executing service %s failed, no config entry found",
|
||||||
|
service_call.service,
|
||||||
|
)
|
||||||
|
|
||||||
for service in (SERVICE_REBOOT, SERVICE_RECONNECT):
|
for service in SERVICE_LIST:
|
||||||
hass.services.async_register(DOMAIN, service, async_call_fritz_service)
|
hass.services.async_register(DOMAIN, service, async_call_fritz_service)
|
||||||
|
|
||||||
|
|
||||||
@ -59,5 +75,5 @@ async def async_unload_services(hass: HomeAssistant) -> None:
|
|||||||
|
|
||||||
hass.data[FRITZ_SERVICES] = False
|
hass.data[FRITZ_SERVICES] = False
|
||||||
|
|
||||||
hass.services.async_remove(DOMAIN, SERVICE_REBOOT)
|
for service in SERVICE_LIST:
|
||||||
hass.services.async_remove(DOMAIN, SERVICE_RECONNECT)
|
hass.services.async_remove(DOMAIN, service)
|
||||||
|
@ -22,3 +22,16 @@ reboot:
|
|||||||
integration: fritz
|
integration: fritz
|
||||||
entity:
|
entity:
|
||||||
device_class: connectivity
|
device_class: connectivity
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
description: Remove FRITZ!Box stale device_tracker entities
|
||||||
|
fields:
|
||||||
|
device_id:
|
||||||
|
name: Fritz!Box Device
|
||||||
|
description: Select the Fritz!Box to check
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
device:
|
||||||
|
integration: fritz
|
||||||
|
entity:
|
||||||
|
device_class: connectivity
|
||||||
|
Loading…
x
Reference in New Issue
Block a user