Home Assistant Unofficial Reference 2024.12.1
services.py
Go to the documentation of this file.
1 """UniFi Network services."""
2 
3 from collections.abc import Mapping
4 from typing import Any
5 
6 from aiounifi.models.client import ClientReconnectRequest, ClientRemoveRequest
7 import voluptuous as vol
8 
9 from homeassistant.config_entries import ConfigEntryState
10 from homeassistant.const import ATTR_DEVICE_ID
11 from homeassistant.core import HomeAssistant, ServiceCall, callback
12 from homeassistant.helpers import device_registry as dr
13 from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
14 
15 from .const import DOMAIN as UNIFI_DOMAIN
16 
17 SERVICE_RECONNECT_CLIENT = "reconnect_client"
18 SERVICE_REMOVE_CLIENTS = "remove_clients"
19 
20 SERVICE_RECONNECT_CLIENT_SCHEMA = vol.All(
21  vol.Schema({vol.Required(ATTR_DEVICE_ID): str})
22 )
23 
24 SUPPORTED_SERVICES = (SERVICE_RECONNECT_CLIENT, SERVICE_REMOVE_CLIENTS)
25 
26 SERVICE_TO_SCHEMA = {
27  SERVICE_RECONNECT_CLIENT: SERVICE_RECONNECT_CLIENT_SCHEMA,
28 }
29 
30 
31 @callback
32 def async_setup_services(hass: HomeAssistant) -> None:
33  """Set up services for UniFi integration."""
34 
35  services = {
36  SERVICE_RECONNECT_CLIENT: async_reconnect_client,
37  SERVICE_REMOVE_CLIENTS: async_remove_clients,
38  }
39 
40  async def async_call_unifi_service(service_call: ServiceCall) -> None:
41  """Call correct UniFi service."""
42  await services[service_call.service](hass, service_call.data)
43 
44  for service in SUPPORTED_SERVICES:
45  hass.services.async_register(
46  UNIFI_DOMAIN,
47  service,
48  async_call_unifi_service,
49  schema=SERVICE_TO_SCHEMA.get(service),
50  )
51 
52 
53 async def async_reconnect_client(hass: HomeAssistant, data: Mapping[str, Any]) -> None:
54  """Try to get wireless client to reconnect to Wi-Fi."""
55  device_registry = dr.async_get(hass)
56  device_entry = device_registry.async_get(data[ATTR_DEVICE_ID])
57 
58  if device_entry is None:
59  return
60 
61  mac = ""
62  for connection in device_entry.connections:
63  if connection[0] == CONNECTION_NETWORK_MAC:
64  mac = connection[1]
65  break
66 
67  if mac == "":
68  return
69 
70  for config_entry in hass.config_entries.async_entries(UNIFI_DOMAIN):
71  if config_entry.state is not ConfigEntryState.LOADED or (
72  (hub := config_entry.runtime_data)
73  and not hub.available
74  or (client := hub.api.clients.get(mac)) is None
75  or client.is_wired
76  ):
77  continue
78 
79  await hub.api.request(ClientReconnectRequest.create(mac))
80 
81 
82 async def async_remove_clients(hass: HomeAssistant, data: Mapping[str, Any]) -> None:
83  """Remove select clients from UniFi Network.
84 
85  Validates based on:
86  - Total time between first seen and last seen is less than 15 minutes.
87  - Neither IP, hostname nor name is configured.
88  """
89  for config_entry in hass.config_entries.async_entries(UNIFI_DOMAIN):
90  if (
91  config_entry.state is not ConfigEntryState.LOADED
92  or (hub := config_entry.runtime_data)
93  and not hub.available
94  ):
95  continue
96 
97  clients_to_remove = []
98 
99  for client in hub.api.clients_all.values():
100  if (
101  client.last_seen
102  and client.first_seen
103  and client.last_seen - client.first_seen > 900
104  ):
105  continue
106 
107  if any({client.fixed_ip, client.hostname, client.name}):
108  continue
109 
110  clients_to_remove.append(client.mac)
111 
112  if clients_to_remove:
113  await hub.api.request(ClientRemoveRequest.create(clients_to_remove))
None async_remove_clients(HomeAssistant hass, Mapping[str, Any] data)
Definition: services.py:82
None async_reconnect_client(HomeAssistant hass, Mapping[str, Any] data)
Definition: services.py:53
None async_setup_services(HomeAssistant hass)
Definition: services.py:32