1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
|
"""Clients are devices on a UniFi network."""
from dataclasses import dataclass
from typing import Self, TypedDict, cast
from .api import ApiItem, ApiRequest
class TypedClient(TypedDict):
"""Client type definition."""
_id: str
_is_guest_by_uap: bool
_is_guest_by_ugw: bool
_is_guest_by_usw: bool
_last_seen_by_uap: int
_last_seen_by_ugw: int
_last_seen_by_usw: int
_uptime_by_uap: int
_uptime_by_ugw: int
_uptime_by_usw: int
anomalies: int
ap_mac: str
assoc_time: int
authorized: bool
blocked: bool
bssid: str
bytes_r: int
ccq: int
channel: int
dev_cat: int
dev_family: int
dev_id: int
dev_id_override: int
dev_vendor: int
device_name: str
dhcpend_time: int
disconnect_timestamp: int
eagerly_discovered: bool
essid: str
fingerprint_engine_version: str
fingerprint_override: bool
fingerprint_source: int
first_seen: int
fixed_ip: str
fw_version: str
gw_mac: str
hostname: str
hostname_source: str
idletime: int
ip: str
is_11r: bool
is_guest: bool
is_wired: bool
last_seen: bool
latest_assoc_time: bool
mac: str
name: str
network: str
network_id: str
noise: int
noted: bool
os_class: int
os_name: int
oui: str
powersave_enabled: bool
qos_policy_applied: bool
radio: str
radio_name: str
radio_proto: str
rssi: int
rx_bytes: int
rx_packets: int
rx_rate: int
satisfaction: int
score: int
signal: int
site_id: str
sw_depth: int
sw_mac: str
sw_port: int
tx_bytes: int
tx_packets: int
tx_power: int
tx_rate: int
tx_retries: int
uptime: int
use_fixedip: bool
user_id: str
usergroup_id: str
vlan: int
wifi_tx_attempts: int
wired_rate_mbps: int
wired_tx_bytes: int
wired_rx_bytes: int
wired_tx_packets: int
wired_rx_packets: int
wired_tx_bytes_r: int
wired_rx_bytes_r: int
@dataclass
class AllClientListRequest(ApiRequest):
"""Request object for all clients list."""
@classmethod
def create(cls) -> Self:
"""Create all clients list request."""
return cls(method="get", path="/rest/user")
@dataclass
class ClientListRequest(ApiRequest):
"""Request object for active client list."""
@classmethod
def create(cls) -> Self:
"""Create active client list request."""
return cls(method="get", path="/stat/sta")
@dataclass
class ClientBlockRequest(ApiRequest):
"""Request object for client block."""
@classmethod
def create(cls, mac: str, block: bool) -> Self:
"""Create client block request."""
return cls(
method="post",
path="/cmd/stamgr",
data={
"cmd": "block-sta" if block else "unblock-sta",
"mac": mac,
},
)
@dataclass
class ClientReconnectRequest(ApiRequest):
"""Request object for client reconnect."""
@classmethod
def create(cls, mac: str) -> Self:
"""Create client reconnect request."""
return cls(
method="post",
path="/cmd/stamgr",
data={
"cmd": "kick-sta",
"mac": mac,
},
)
@dataclass
class ClientRemoveRequest(ApiRequest):
"""Request object for client removal."""
@classmethod
def create(cls, macs: list[str]) -> Self:
"""Create client removal request."""
return cls(
method="post",
path="/cmd/stamgr",
data={
"cmd": "forget-sta",
"macs": macs,
},
)
class Client(ApiItem):
"""Represents a client network device."""
raw: TypedClient
@property
def access_point_mac(self) -> str:
"""MAC address of access point."""
return self.raw.get("ap_mac", "")
@property
def association_time(self) -> int:
"""When was client associated with controller."""
return self.raw.get("assoc_time", 0)
@property
def blocked(self) -> bool:
"""Is client blocked."""
return self.raw.get("blocked", False)
@property
def device_name(self) -> str:
"""Device name of client."""
return self.raw.get("device_name", "")
@property
def essid(self) -> str:
"""ESSID client is connected to."""
return self.raw.get("essid", "")
@property
def firmware_version(self) -> str:
"""Firmware version of client."""
return self.raw.get("fw_version", "")
@property
def first_seen(self) -> int:
"""When was client first seen."""
return self.raw.get("first_seen", 0)
@property
def fixed_ip(self) -> str:
"""List IP if fixed IP is configured."""
return self.raw.get("fixed_ip", "")
@property
def hostname(self) -> str:
"""Hostname of client."""
return self.raw.get("hostname", "")
@property
def idle_time(self) -> int:
"""Idle time of client."""
return self.raw.get("idletime", 0)
@property
def ip(self) -> str:
"""IP of client."""
return self.raw.get("ip", "")
@property
def is_guest(self) -> bool:
"""Is client guest."""
return self.raw.get("is_guest", False)
@property
def is_wired(self) -> bool:
"""Is client wired."""
return self.raw.get("is_wired", False)
@property
def last_seen(self) -> int:
"""When was client last seen."""
return self.raw.get("last_seen", 0)
@property
def last_seen_by_access_point(self) -> int:
"""When was client last seen by access point."""
return self.raw.get("_last_seen_by_uap", 0)
@property
def last_seen_by_gateway(self) -> int:
"""When was client last seen by gateway."""
return self.raw.get("_last_seen_by_ugw", 0)
@property
def last_seen_by_switch(self) -> int:
"""When was client last seen by network switch."""
return self.raw.get("_last_seen_by_usw", 0)
@property
def latest_association_time(self) -> int:
"""When was client last associated with controller."""
return self.raw.get("latest_assoc_time", 0)
@property
def mac(self) -> str:
"""MAC address of client."""
return self.raw.get("mac", "")
@property
def name(self) -> str:
"""Name of client."""
return self.raw.get("name", "")
@property
def oui(self) -> str:
"""Vendor string for client MAC."""
return self.raw.get("oui", "")
@property
def powersave_enabled(self) -> bool | None:
"""Powersave functionality enabled for wireless client."""
return self.raw.get("powersave_enabled")
@property
def site_id(self) -> str:
"""Site ID client belongs to."""
return self.raw.get("site_id", "")
@property
def switch_depth(self) -> int | None:
"""How many layers of switches client is in."""
return self.raw.get("sw_depth")
@property
def switch_mac(self) -> str:
"""MAC for switch client is connected to."""
return self.raw.get("sw_mac", "")
@property
def switch_port(self) -> int | None:
"""Switch port client is connected to."""
return self.raw.get("sw_port")
@property
def rx_bytes(self) -> int:
"""Bytes received over wireless connection."""
return self.raw.get("rx_bytes", 0)
@property
def rx_bytes_r(self) -> float:
"""Bytes recently received over wireless connection."""
return cast(float, self.raw.get("rx_bytes-r", 0.0))
@property
def tx_bytes(self) -> int:
"""Bytes transferred over wireless connection."""
return self.raw.get("tx_bytes", 0)
@property
def tx_bytes_r(self) -> float:
"""Bytes recently transferred over wireless connection."""
return cast(float, self.raw.get("tx_bytes-r", 0.0))
@property
def uptime(self) -> int:
"""Uptime of client."""
return self.raw.get("uptime", 0)
@property
def uptime_by_access_point(self) -> int:
"""Uptime of client observed by access point."""
return self.raw.get("_uptime_by_uap", 0)
@property
def uptime_by_gateway(self) -> int:
"""Uptime of client observed by gateway."""
return self.raw.get("_uptime_by_ugw", 0)
@property
def uptime_by_switch(self) -> int:
"""Uptime of client observed by network switch."""
return self.raw.get("_uptime_by_usw", 0)
@property
def wired_rate_mbps(self) -> int:
"""Wired rate in Mbps."""
return self.raw.get("wired_rate_mbps", 0)
@property
def wired_rx_bytes(self) -> int:
"""Bytes received over wired connection."""
return cast(int, self.raw.get("wired-rx_bytes", 0))
@property
def wired_rx_bytes_r(self) -> float:
"""Bytes recently received over wired connection."""
return cast(float, self.raw.get("wired-rx_bytes-r", 0.0))
@property
def wired_tx_bytes(self) -> int:
"""Bytes transferred over wired connection."""
return cast(int, self.raw.get("wired-tx_bytes", 0))
@property
def wired_tx_bytes_r(self) -> float:
"""Bytes recently transferred over wired connection."""
return cast(float, self.raw.get("wired-tx_bytes-r", 0.0))
|