uiprotect 0.12.0__py3-none-any.whl → 0.14.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
@@ -14,10 +14,10 @@ from uuid import UUID
14
14
  from ..exceptions import BadRequest, ClientError, NotAuthorized
15
15
  from ..utils import (
16
16
  asyncio_timeout,
17
+ convert_to_datetime,
17
18
  convert_unifi_data,
18
19
  dict_diff,
19
20
  is_debug,
20
- process_datetime,
21
21
  serialize_unifi_obj,
22
22
  to_snake_case,
23
23
  )
@@ -850,9 +850,9 @@ class ProtectDeviceModel(ProtectModelWithId):
850
850
  @classmethod
851
851
  def unifi_dict_to_dict(cls, data: dict[str, Any]) -> dict[str, Any]:
852
852
  if "lastSeen" in data:
853
- data["lastSeen"] = process_datetime(data, "lastSeen")
853
+ data["lastSeen"] = convert_to_datetime(data["lastSeen"])
854
854
  if "upSince" in data and data["upSince"] is not None:
855
- data["upSince"] = process_datetime(data, "upSince")
855
+ data["upSince"] = convert_to_datetime(data["upSince"])
856
856
  if (
857
857
  "uptime" in data
858
858
  and data["uptime"] is not None
@@ -1001,7 +1001,7 @@ class ProtectAdoptableDeviceModel(ProtectDeviceModel):
1001
1001
  @classmethod
1002
1002
  def unifi_dict_to_dict(cls, data: dict[str, Any]) -> dict[str, Any]:
1003
1003
  if "lastDisconnect" in data and data["lastDisconnect"] is not None:
1004
- data["lastDisconnect"] = process_datetime(data, "lastDisconnect")
1004
+ data["lastDisconnect"] = convert_to_datetime(data["lastDisconnect"])
1005
1005
 
1006
1006
  return super().unifi_dict_to_dict(data)
1007
1007
 
@@ -131,26 +131,34 @@ def _process_sensor_event(event: Event) -> None:
131
131
  event.sensor.last_value_event_id = event.id
132
132
 
133
133
 
134
+ _CAMERA_SMART_AND_LINE_EVENTS = {
135
+ EventType.SMART_DETECT,
136
+ EventType.SMART_DETECT_LINE,
137
+ }
138
+ _CAMERA_SMART_AUDIO_EVENT = EventType.SMART_AUDIO_DETECT
139
+
140
+
134
141
  def _process_camera_event(event: Event) -> None:
135
- if event.camera is None:
142
+ if (camera := event.camera) is None:
136
143
  return
137
144
 
138
- dt_attr, event_attr = CAMERA_EVENT_ATTR_MAP[event.type]
139
- dt = getattr(event.camera, dt_attr)
145
+ event_type = event.type
146
+ dt_attr, event_attr = CAMERA_EVENT_ATTR_MAP[event_type]
147
+ dt = getattr(camera, dt_attr)
140
148
  if dt is None or event.start >= dt or (event.end is not None and event.end >= dt):
141
- setattr(event.camera, event_attr, event.id)
142
- setattr(event.camera, dt_attr, event.start)
143
- if event.type in {EventType.SMART_DETECT, EventType.SMART_DETECT_LINE}:
149
+ setattr(camera, event_attr, event.id)
150
+ setattr(camera, dt_attr, event.start)
151
+ if event_type in _CAMERA_SMART_AND_LINE_EVENTS:
144
152
  for smart_type in event.smart_detect_types:
145
- event.camera.last_smart_detect_event_ids[smart_type] = event.id
146
- event.camera.last_smart_detects[smart_type] = event.start
147
- elif event.type == EventType.SMART_AUDIO_DETECT:
153
+ camera.last_smart_detect_event_ids[smart_type] = event.id
154
+ camera.last_smart_detects[smart_type] = event.start
155
+ elif event_type is _CAMERA_SMART_AUDIO_EVENT:
148
156
  for smart_type in event.smart_detect_types:
149
157
  audio_type = smart_type.audio_type
150
158
  if audio_type is None:
151
159
  continue
152
- event.camera.last_smart_audio_detect_event_ids[audio_type] = event.id
153
- event.camera.last_smart_audio_detects[audio_type] = event.start
160
+ camera.last_smart_audio_detect_event_ids[audio_type] = event.id
161
+ camera.last_smart_audio_detects[audio_type] = event.start
154
162
 
155
163
 
156
164
  @dataclass
@@ -212,7 +220,7 @@ class Bootstrap(ProtectBaseObject):
212
220
  data["macLookup"] = {}
213
221
  data["idLookup"] = {}
214
222
  for model_type in ModelType.bootstrap_models():
215
- key = model_type + "s"
223
+ key = f"{model_type}s"
216
224
  items: dict[str, ProtectModel] = {}
217
225
  for item in data[key]:
218
226
  if (
@@ -249,7 +257,7 @@ class Bootstrap(ProtectBaseObject):
249
257
  del data["idLookup"]
250
258
 
251
259
  for model_type in ModelType.bootstrap_models():
252
- attr = model_type + "s"
260
+ attr = f"{model_type}s"
253
261
  if attr in data and isinstance(data[attr], dict):
254
262
  data[attr] = list(data[attr].values())
255
263
 
@@ -379,7 +387,7 @@ class Bootstrap(ProtectBaseObject):
379
387
  and obj.model is not None
380
388
  and obj.model.value in ModelType.bootstrap_models_set()
381
389
  ):
382
- key = obj.model.value + "s"
390
+ key = f"{obj.model.value}s"
383
391
  if not self.api.ignore_unadopted or (
384
392
  obj.is_adopted and not obj.is_adopted_by_other
385
393
  ):
uiprotect/data/devices.py CHANGED
@@ -23,9 +23,9 @@ from ..utils import (
23
23
  clamp_value,
24
24
  convert_smart_audio_types,
25
25
  convert_smart_types,
26
+ convert_to_datetime,
26
27
  convert_video_modes,
27
28
  from_js_time,
28
- process_datetime,
29
29
  serialize_point,
30
30
  to_js_time,
31
31
  utc_now,
@@ -494,7 +494,7 @@ class LCDMessage(ProtectBaseObject):
494
494
  @classmethod
495
495
  def unifi_dict_to_dict(cls, data: dict[str, Any]) -> dict[str, Any]:
496
496
  if "resetAt" in data:
497
- data["resetAt"] = process_datetime(data, "resetAt")
497
+ data["resetAt"] = convert_to_datetime(data["resetAt"])
498
498
  if "text" in data:
499
499
  # UniFi Protect bug: some times LCD messages can get into a bad state where message = DEFAULT MESSAGE, but no type
500
500
  if "type" not in data:
@@ -579,21 +579,21 @@ class VideoStats(ProtectBaseObject):
579
579
  @classmethod
580
580
  def unifi_dict_to_dict(cls, data: dict[str, Any]) -> dict[str, Any]:
581
581
  if "recordingStart" in data:
582
- data["recordingStart"] = process_datetime(data, "recordingStart")
582
+ data["recordingStart"] = convert_to_datetime(data["recordingStart"])
583
583
  if "recordingEnd" in data:
584
- data["recordingEnd"] = process_datetime(data, "recordingEnd")
584
+ data["recordingEnd"] = convert_to_datetime(data["recordingEnd"])
585
585
  if "recordingStartLQ" in data:
586
- data["recordingStartLQ"] = process_datetime(data, "recordingStartLQ")
586
+ data["recordingStartLQ"] = convert_to_datetime(data["recordingStartLQ"])
587
587
  if "recordingEndLQ" in data:
588
- data["recordingEndLQ"] = process_datetime(data, "recordingEndLQ")
588
+ data["recordingEndLQ"] = convert_to_datetime(data["recordingEndLQ"])
589
589
  if "timelapseStart" in data:
590
- data["timelapseStart"] = process_datetime(data, "timelapseStart")
590
+ data["timelapseStart"] = convert_to_datetime(data["timelapseStart"])
591
591
  if "timelapseEnd" in data:
592
- data["timelapseEnd"] = process_datetime(data, "timelapseEnd")
592
+ data["timelapseEnd"] = convert_to_datetime(data["timelapseEnd"])
593
593
  if "timelapseStartLQ" in data:
594
- data["timelapseStartLQ"] = process_datetime(data, "timelapseStartLQ")
594
+ data["timelapseStartLQ"] = convert_to_datetime(data["timelapseStartLQ"])
595
595
  if "timelapseEndLQ" in data:
596
- data["timelapseEndLQ"] = process_datetime(data, "timelapseEndLQ")
596
+ data["timelapseEndLQ"] = convert_to_datetime(data["timelapseEndLQ"])
597
597
 
598
598
  return super().unifi_dict_to_dict(data)
599
599
 
uiprotect/data/nvr.py CHANGED
@@ -17,7 +17,7 @@ import orjson
17
17
  from aiofiles import os as aos
18
18
 
19
19
  from ..exceptions import BadRequest, NotAuthorized
20
- from ..utils import RELEASE_CACHE, process_datetime
20
+ from ..utils import RELEASE_CACHE, convert_to_datetime
21
21
  from .base import (
22
22
  ProtectBaseObject,
23
23
  ProtectDeviceModel,
@@ -170,7 +170,7 @@ class EventDetectedThumbnail(ProtectBaseObject):
170
170
  def unifi_dict_to_dict(cls, data: dict[str, Any]) -> dict[str, Any]:
171
171
  if "clockBestWall" in data:
172
172
  if data["clockBestWall"]:
173
- data["clockBestWall"] = process_datetime(data, "clockBestWall")
173
+ data["clockBestWall"] = convert_to_datetime(data["clockBestWall"])
174
174
  else:
175
175
  del data["clockBestWall"]
176
176
 
@@ -309,7 +309,7 @@ class Event(ProtectModelWithId):
309
309
  @classmethod
310
310
  def unifi_dict_to_dict(cls, data: dict[str, Any]) -> dict[str, Any]:
311
311
  for key in {"start", "end", "timestamp", "deletedAt"}.intersection(data):
312
- data[key] = process_datetime(data, key)
312
+ data[key] = convert_to_datetime(data[key])
313
313
 
314
314
  return super().unifi_dict_to_dict(data)
315
315
 
@@ -1025,11 +1025,10 @@ class NVR(ProtectDeviceModel):
1025
1025
  @classmethod
1026
1026
  def unifi_dict_to_dict(cls, data: dict[str, Any]) -> dict[str, Any]:
1027
1027
  if "lastUpdateAt" in data:
1028
- data["lastUpdateAt"] = process_datetime(data, "lastUpdateAt")
1028
+ data["lastUpdateAt"] = convert_to_datetime(data["lastUpdateAt"])
1029
1029
  if "lastDeviceFwUpdatesCheckedAt" in data:
1030
- data["lastDeviceFwUpdatesCheckedAt"] = process_datetime(
1031
- data,
1032
- "lastDeviceFwUpdatesCheckedAt",
1030
+ data["lastDeviceFwUpdatesCheckedAt"] = convert_to_datetime(
1031
+ data["lastDeviceFwUpdatesCheckedAt"]
1033
1032
  )
1034
1033
  if (
1035
1034
  "recordingRetentionDurationMs" in data
uiprotect/utils.py CHANGED
@@ -172,9 +172,10 @@ def from_js_time(num: float | str | datetime) -> datetime:
172
172
  return datetime.fromtimestamp(int(num) / 1000, tz=timezone.utc)
173
173
 
174
174
 
175
- def process_datetime(data: dict[str, Any], key: str) -> datetime | None:
176
- """Extracts datetime object from Protect dictionary"""
177
- return None if data.get(key) is None else from_js_time(data[key])
175
+ @lru_cache(maxsize=1024)
176
+ def convert_to_datetime(source_time: float | str | datetime | None) -> datetime | None:
177
+ """Converts timestamp to datetime object"""
178
+ return None if source_time is None else from_js_time(source_time)
178
179
 
179
180
 
180
181
  def format_datetime(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: uiprotect
3
- Version: 0.12.0
3
+ Version: 0.14.0
4
4
  Summary: Python API for Unifi Protect (Unofficial)
5
5
  Home-page: https://github.com/uilibs/uiprotect
6
6
  License: MIT
@@ -14,11 +14,11 @@ 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=ex-UC9CJUtzxMFqtYokSiXM8pNHVBqCzq7r8WrEf1Mw,37178
18
- uiprotect/data/bootstrap.py,sha256=RcqIiIk8z5QKDMnrWB7ZZDlBouesx2xQGN02wEl-B9s,21416
17
+ uiprotect/data/base.py,sha256=TkhnYoHxYFmtg30rFOYQjmk7uw2Ky7dMSS-cV6FGLnw,37190
18
+ uiprotect/data/bootstrap.py,sha256=cFp8PmsRLcz_hKFn50n2BBPNZcnI_RJvEF9GYEXKPOg,21543
19
19
  uiprotect/data/convert.py,sha256=rOQplUMIdTMD2SbAx_iI9BNPDscnhDvyRVLEMDhtADg,2047
20
- uiprotect/data/devices.py,sha256=LHVBT8ihMAZen7gIlQNbiYxukRrBpi_TNKNmV_5R6Xc,111705
21
- uiprotect/data/nvr.py,sha256=OJso6oewA_jY7ovKbD2U2Onp1GqheT5bCW0F6dC53DQ,47570
20
+ uiprotect/data/devices.py,sha256=yx30uYnAlzabVhMohdDkO6LMgEuC7kSwUJbX5LWXHnA,111735
21
+ uiprotect/data/nvr.py,sha256=At4N2trpfMk-wMXViBe7Lp_a5ML4JnOXOnDIVr3vPDI,47568
22
22
  uiprotect/data/types.py,sha256=6Z5ZqWTbH4Igy0l4QJShqQZ_zvrJKD0G-hZLjoBNP-U,16193
23
23
  uiprotect/data/user.py,sha256=yBnUQ3qpHL745hLhR41WjWv_Yx51RlmfHapgvK0KSgM,7067
24
24
  uiprotect/data/websocket.py,sha256=WZJVA7EfYuKYMv-9jmvGgMWXKzE9ES25SKv1NQ2eHjc,6281
@@ -28,10 +28,10 @@ uiprotect/release_cache.json,sha256=NamnSFy78hOWY0DPO87J9ELFCAN6NnVquv8gQO75ZG4,
28
28
  uiprotect/stream.py,sha256=McV3XymKyjn-1uV5jdQHcpaDjqLS4zWyMASQ8ubcyb4,4924
29
29
  uiprotect/test_util/__init__.py,sha256=d2g7afa0LSdixQ0kjEDYwafDFME_UlW2LzxpamZ2BC0,18556
30
30
  uiprotect/test_util/anonymize.py,sha256=f-8ijU-_y9r-uAbhIPn0f0I6hzJpAkvJzc8UpWihObI,8478
31
- uiprotect/utils.py,sha256=ItYUrIhCbvdvIO3Q_MI9jQFnFs5OouqfsO_SXWeQZPM,18389
31
+ uiprotect/utils.py,sha256=6OLY8hNiCzk418PjJJIlFW7jjPzVt1vxBKEzBSqMeTk,18418
32
32
  uiprotect/websocket.py,sha256=iMTdchymaCgVHsmY1bRbxkcymqt6WQircIHYNxCu178,7289
33
- uiprotect-0.12.0.dist-info/LICENSE,sha256=INx18jhdbVXMEiiBANeKEbrbz57ckgzxk5uutmmcxGk,1111
34
- uiprotect-0.12.0.dist-info/METADATA,sha256=13ADAWhiHnb4kCgVFsioRdR_pYLaGG4vDYQzdDfIcU0,10985
35
- uiprotect-0.12.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
36
- uiprotect-0.12.0.dist-info/entry_points.txt,sha256=J78AUTPrTTxgI3s7SVgrmGqDP7piX2wuuEORzhDdVRA,47
37
- uiprotect-0.12.0.dist-info/RECORD,,
33
+ uiprotect-0.14.0.dist-info/LICENSE,sha256=INx18jhdbVXMEiiBANeKEbrbz57ckgzxk5uutmmcxGk,1111
34
+ uiprotect-0.14.0.dist-info/METADATA,sha256=0Y-f0uuYI6g81m3TwXC102R5wUtTw0VWIlvJQizQ81w,10985
35
+ uiprotect-0.14.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
36
+ uiprotect-0.14.0.dist-info/entry_points.txt,sha256=J78AUTPrTTxgI3s7SVgrmGqDP7piX2wuuEORzhDdVRA,47
37
+ uiprotect-0.14.0.dist-info/RECORD,,