uiprotect 1.11.0__py3-none-any.whl → 1.12.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of uiprotect might be problematic. Click here for more details.

uiprotect/data/base.py CHANGED
@@ -6,7 +6,7 @@ import asyncio
6
6
  import logging
7
7
  from collections.abc import Callable
8
8
  from datetime import datetime, timedelta
9
- from functools import cache, cached_property
9
+ from functools import cache
10
10
  from ipaddress import IPv4Address
11
11
  from typing import TYPE_CHECKING, Any, ClassVar, TypeVar
12
12
  from uuid import UUID
@@ -89,7 +89,6 @@ class ProtectBaseObject(BaseModel):
89
89
  arbitrary_types_allowed = True
90
90
  validate_assignment = True
91
91
  copy_on_model_validation = "shallow"
92
- keep_untouched = (cached_property,)
93
92
 
94
93
  def __init__(self, api: ProtectApiClient | None = None, **data: Any) -> None:
95
94
  """
@@ -8,7 +8,7 @@ from collections.abc import Iterable
8
8
  from copy import deepcopy
9
9
  from dataclasses import dataclass
10
10
  from datetime import datetime
11
- from functools import cache, cached_property
11
+ from functools import cache
12
12
  from typing import TYPE_CHECKING, Any, cast
13
13
 
14
14
  from aiohttp.client_exceptions import ServerDisconnectedError
@@ -56,6 +56,7 @@ _LOGGER = logging.getLogger(__name__)
56
56
  MAX_SUPPORTED_CAMERAS = 256
57
57
  MAX_EVENT_HISTORY_IN_STATE_MACHINE = MAX_SUPPORTED_CAMERAS * 2
58
58
  STATS_KEYS = {
59
+ "eventStats",
59
60
  "storageStats",
60
61
  "stats",
61
62
  "systemInfo",
@@ -181,6 +182,10 @@ class Bootstrap(ProtectBaseObject):
181
182
  mac_lookup: dict[str, ProtectDeviceRef] = {}
182
183
  id_lookup: dict[str, ProtectDeviceRef] = {}
183
184
  _ws_stats: list[WSStat] = PrivateAttr([])
185
+ _has_doorbell: bool | None = PrivateAttr(None)
186
+ _has_smart: bool | None = PrivateAttr(None)
187
+ _has_media: bool | None = PrivateAttr(None)
188
+ _recording_start: datetime | None = PrivateAttr(None)
184
189
  _refresh_tasks: set[asyncio.Task[None]] = PrivateAttr(set())
185
190
 
186
191
  @classmethod
@@ -248,33 +253,48 @@ class Bootstrap(ProtectBaseObject):
248
253
  def auth_user(self) -> User:
249
254
  return self._api.bootstrap.users[self.auth_user_id]
250
255
 
251
- @cached_property
256
+ @property
252
257
  def has_doorbell(self) -> bool:
253
- return any(c.feature_flags.is_doorbell for c in self.cameras.values())
258
+ if self._has_doorbell is None:
259
+ self._has_doorbell = any(
260
+ c.feature_flags.is_doorbell for c in self.cameras.values()
261
+ )
254
262
 
255
- @cached_property
263
+ return self._has_doorbell
264
+
265
+ @property
256
266
  def recording_start(self) -> datetime | None:
257
- """Get earliest recording date."""
258
- try:
259
- return min(
260
- c.stats.video.recording_start
261
- for c in self.cameras.values()
262
- if c.stats.video.recording_start is not None
263
- )
264
- except ValueError:
265
- return None
267
+ """Get earilest recording date."""
268
+ if self._recording_start is None:
269
+ try:
270
+ self._recording_start = min(
271
+ c.stats.video.recording_start
272
+ for c in self.cameras.values()
273
+ if c.stats.video.recording_start is not None
274
+ )
275
+ except ValueError:
276
+ return None
277
+ return self._recording_start
266
278
 
267
- @cached_property
279
+ @property
268
280
  def has_smart_detections(self) -> bool:
269
281
  """Check if any camera has smart detections."""
270
- return any(c.feature_flags.has_smart_detect for c in self.cameras.values())
282
+ if self._has_smart is None:
283
+ self._has_smart = any(
284
+ c.feature_flags.has_smart_detect for c in self.cameras.values()
285
+ )
286
+ return self._has_smart
271
287
 
272
- @cached_property
288
+ @property
273
289
  def has_media(self) -> bool:
274
290
  """Checks if user can read media for any camera."""
275
- if self.recording_start is None:
276
- return False
277
- return any(c.can_read_media(self.auth_user) for c in self.cameras.values())
291
+ if self._has_media is None:
292
+ if self.recording_start is None:
293
+ return False
294
+ self._has_media = any(
295
+ c.can_read_media(self.auth_user) for c in self.cameras.values()
296
+ )
297
+ return self._has_media
278
298
 
279
299
  def get_device_from_mac(self, mac: str) -> ProtectAdoptableDeviceModel | None:
280
300
  """Retrieve a device from MAC address."""
@@ -375,8 +395,7 @@ class Bootstrap(ProtectBaseObject):
375
395
 
376
396
  device_id: str = packet.action_frame.data["id"]
377
397
  self.id_lookup.pop(device_id, None)
378
- device = devices.pop(device_id, None)
379
- if device is None:
398
+ if (device := devices.pop(device_id, None)) is None:
380
399
  return None
381
400
  self.mac_lookup.pop(normalize_mac(device.mac), None)
382
401
 
@@ -467,19 +486,17 @@ class Bootstrap(ProtectBaseObject):
467
486
  elif model_type is ModelType.CAMERA:
468
487
  if TYPE_CHECKING:
469
488
  assert isinstance(obj, Camera)
470
- if "last_ring" in data and obj.last_ring:
471
- is_recent = obj.last_ring + RECENT_EVENT_MAX >= utc_now()
472
- _LOGGER.debug("last_ring for %s (%s)", obj.id, is_recent)
473
- if is_recent:
489
+ if "last_ring" in data and (last_ring := obj.last_ring):
490
+ if is_recent := last_ring + RECENT_EVENT_MAX >= utc_now():
474
491
  obj.set_ring_timeout()
492
+ _LOGGER.debug("last_ring for %s (%s)", obj.id, is_recent)
475
493
  elif model_type is ModelType.SENSOR:
476
494
  if TYPE_CHECKING:
477
495
  assert isinstance(obj, Sensor)
478
- if "alarm_triggered_at" in data and obj.alarm_triggered_at:
479
- is_recent = obj.alarm_triggered_at + RECENT_EVENT_MAX >= utc_now()
480
- _LOGGER.debug("alarm_triggered_at for %s (%s)", obj.id, is_recent)
481
- if is_recent:
496
+ if "alarm_triggered_at" in data and (trigged_at := obj.alarm_triggered_at):
497
+ if is_recent := trigged_at + RECENT_EVENT_MAX >= utc_now():
482
498
  obj.set_alarm_timeout()
499
+ _LOGGER.debug("alarm_triggered_at for %s (%s)", obj.id, is_recent)
483
500
 
484
501
  devices[action_id] = obj
485
502
  self._create_stat(packet, data, False)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: uiprotect
3
- Version: 1.11.0
3
+ Version: 1.12.0
4
4
  Summary: Python API for Unifi Protect (Unofficial)
5
5
  Home-page: https://github.com/uilibs/uiprotect
6
6
  License: MIT
@@ -14,8 +14,8 @@ uiprotect/cli/nvr.py,sha256=TwxEg2XT8jXAbOqv6gc7KFXELKadeItEDYweSL4_-e8,4260
14
14
  uiprotect/cli/sensors.py,sha256=fQtcDJCVxs4VbAqcavgBy2ABiVxAW3GXtna6_XFBp2k,8153
15
15
  uiprotect/cli/viewers.py,sha256=2cyrp104ffIvgT0wYGIO0G35QMkEbFe7fSVqLwDXQYQ,2171
16
16
  uiprotect/data/__init__.py,sha256=OcfuJl2qXfHcj_mdnrHhzZ5tEIZrw8auziX5IE7dn-I,2938
17
- uiprotect/data/base.py,sha256=MdMICVAbsY2apzdsf9oy-PmVKNlZzG_w96pTbdzOHp4,37635
18
- uiprotect/data/bootstrap.py,sha256=VW2Qm2n2gP6vS4uxKEa-leCrQplvWhVxieQ5Wx0xhqM,20873
17
+ uiprotect/data/base.py,sha256=apIXKZHL6dbyXTT4C4lkyo4M-Nf_DwsVXoXBL5jcXVo,37574
18
+ uiprotect/data/bootstrap.py,sha256=pAb-JC_AatYPldfefiMqdZ3_6Ftngcmd2asAMw66XLE,21486
19
19
  uiprotect/data/convert.py,sha256=8h6Il_DhMkPRDPj9F_rA2UZIlTuchS3BQD24peKpk2A,2185
20
20
  uiprotect/data/devices.py,sha256=Nq3bOko5PFf5LvEBoD4JV8kmbq50laRdh3VHMWX7t-0,111809
21
21
  uiprotect/data/nvr.py,sha256=XC4NO1c_Mom-hIpzj9ksKFcgKbHd6ToqWjkgzxJ1PJY,47636
@@ -30,8 +30,8 @@ uiprotect/test_util/__init__.py,sha256=d2g7afa0LSdixQ0kjEDYwafDFME_UlW2LzxpamZ2B
30
30
  uiprotect/test_util/anonymize.py,sha256=f-8ijU-_y9r-uAbhIPn0f0I6hzJpAkvJzc8UpWihObI,8478
31
31
  uiprotect/utils.py,sha256=6OLY8hNiCzk418PjJJIlFW7jjPzVt1vxBKEzBSqMeTk,18418
32
32
  uiprotect/websocket.py,sha256=IzDPyqbzrkOMREvahN-e2zdvVD0VABSCWy6jSoCwOT0,7299
33
- uiprotect-1.11.0.dist-info/LICENSE,sha256=INx18jhdbVXMEiiBANeKEbrbz57ckgzxk5uutmmcxGk,1111
34
- uiprotect-1.11.0.dist-info/METADATA,sha256=rH_zlA9LJvqKScUh8yJWT4eJuVjb-YdE_20BLANPKgc,10985
35
- uiprotect-1.11.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
36
- uiprotect-1.11.0.dist-info/entry_points.txt,sha256=J78AUTPrTTxgI3s7SVgrmGqDP7piX2wuuEORzhDdVRA,47
37
- uiprotect-1.11.0.dist-info/RECORD,,
33
+ uiprotect-1.12.0.dist-info/LICENSE,sha256=INx18jhdbVXMEiiBANeKEbrbz57ckgzxk5uutmmcxGk,1111
34
+ uiprotect-1.12.0.dist-info/METADATA,sha256=wPRYZLr1EpqqtUnuenaK3Z-iEdmDqA4YnHCvJG5NQAY,10985
35
+ uiprotect-1.12.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
36
+ uiprotect-1.12.0.dist-info/entry_points.txt,sha256=J78AUTPrTTxgI3s7SVgrmGqDP7piX2wuuEORzhDdVRA,47
37
+ uiprotect-1.12.0.dist-info/RECORD,,