uiprotect 1.15.0__tar.gz → 1.17.0__tar.gz
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-1.15.0 → uiprotect-1.17.0}/PKG-INFO +1 -1
- {uiprotect-1.15.0 → uiprotect-1.17.0}/pyproject.toml +1 -1
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/data/base.py +20 -49
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/data/bootstrap.py +1 -7
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/data/devices.py +23 -32
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/data/nvr.py +3 -3
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/data/websocket.py +13 -11
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/utils.py +4 -6
- {uiprotect-1.15.0 → uiprotect-1.17.0}/LICENSE +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/README.md +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/__init__.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/__main__.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/api.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/cli/__init__.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/cli/backup.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/cli/base.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/cli/cameras.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/cli/chimes.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/cli/doorlocks.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/cli/events.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/cli/lights.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/cli/liveviews.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/cli/nvr.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/cli/sensors.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/cli/viewers.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/data/__init__.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/data/convert.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/data/types.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/data/user.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/exceptions.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/py.typed +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/release_cache.json +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/stream.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/test_util/__init__.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/test_util/anonymize.py +0 -0
- {uiprotect-1.15.0 → uiprotect-1.17.0}/src/uiprotect/websocket.py +0 -0
|
@@ -185,12 +185,6 @@ class ProtectBaseObject(BaseModel):
|
|
|
185
185
|
"""
|
|
186
186
|
return {}
|
|
187
187
|
|
|
188
|
-
@classmethod
|
|
189
|
-
@cache
|
|
190
|
-
def _get_unifi_remaps_set(self) -> set[str]:
|
|
191
|
-
"""Helper method to get set of all child UFP objects."""
|
|
192
|
-
return set(self._get_unifi_remaps())
|
|
193
|
-
|
|
194
188
|
@classmethod
|
|
195
189
|
@cache
|
|
196
190
|
def _get_to_unifi_remaps(cls) -> dict[str, str]:
|
|
@@ -238,9 +232,9 @@ class ProtectBaseObject(BaseModel):
|
|
|
238
232
|
|
|
239
233
|
@classmethod
|
|
240
234
|
@cache
|
|
241
|
-
def
|
|
242
|
-
"""Helper method to get all
|
|
243
|
-
return set(cls._get_protect_objs())
|
|
235
|
+
def _get_excluded_fields(cls) -> set[str]:
|
|
236
|
+
"""Helper method to get all excluded fields for the current object."""
|
|
237
|
+
return set(cls._get_protect_objs()) | set(cls._get_protect_lists())
|
|
244
238
|
|
|
245
239
|
@classmethod
|
|
246
240
|
@cache
|
|
@@ -251,12 +245,6 @@ class ProtectBaseObject(BaseModel):
|
|
|
251
245
|
assert cls._protect_lists is not None
|
|
252
246
|
return cls._protect_lists
|
|
253
247
|
|
|
254
|
-
@classmethod
|
|
255
|
-
@cache
|
|
256
|
-
def _get_protect_lists_set(cls) -> set[str]:
|
|
257
|
-
"""Helper method to get all child UFP objects"""
|
|
258
|
-
return set(cls._get_protect_lists())
|
|
259
|
-
|
|
260
248
|
@classmethod
|
|
261
249
|
@cache
|
|
262
250
|
def _get_protect_dicts(cls) -> dict[str, type[ProtectBaseObject]]:
|
|
@@ -266,12 +254,6 @@ class ProtectBaseObject(BaseModel):
|
|
|
266
254
|
assert cls._protect_dicts is not None
|
|
267
255
|
return cls._protect_dicts
|
|
268
256
|
|
|
269
|
-
@classmethod
|
|
270
|
-
@cache
|
|
271
|
-
def _get_protect_dicts_set(cls) -> set[str]:
|
|
272
|
-
"""Helper method to get all child UFP objects"""
|
|
273
|
-
return set(cls._get_protect_dicts())
|
|
274
|
-
|
|
275
257
|
@classmethod
|
|
276
258
|
def _clean_protect_obj(
|
|
277
259
|
cls,
|
|
@@ -401,15 +383,12 @@ class ProtectBaseObject(BaseModel):
|
|
|
401
383
|
if not isinstance(value, list):
|
|
402
384
|
return value
|
|
403
385
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
if isinstance(item, ProtectBaseObject)
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
items.append(new_item)
|
|
411
|
-
|
|
412
|
-
return items
|
|
386
|
+
return [
|
|
387
|
+
item.unifi_dict()
|
|
388
|
+
if isinstance(item, ProtectBaseObject)
|
|
389
|
+
else klass.construct({}).unifi_dict(data=item) # type: ignore[arg-type]
|
|
390
|
+
for item in value
|
|
391
|
+
]
|
|
413
392
|
|
|
414
393
|
def _unifi_dict_protect_obj_dict(
|
|
415
394
|
self,
|
|
@@ -424,13 +403,10 @@ class ProtectBaseObject(BaseModel):
|
|
|
424
403
|
if not isinstance(value, dict):
|
|
425
404
|
return value
|
|
426
405
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
items[obj_key] = obj
|
|
432
|
-
|
|
433
|
-
return items
|
|
406
|
+
return {
|
|
407
|
+
obj_key: obj.unifi_dict() if isinstance(obj, ProtectBaseObject) else obj
|
|
408
|
+
for obj_key, obj in value.items()
|
|
409
|
+
}
|
|
434
410
|
|
|
435
411
|
def unifi_dict(
|
|
436
412
|
self,
|
|
@@ -454,9 +430,7 @@ class ProtectBaseObject(BaseModel):
|
|
|
454
430
|
"""
|
|
455
431
|
use_obj = False
|
|
456
432
|
if data is None:
|
|
457
|
-
excluded_fields = (
|
|
458
|
-
self._get_protect_objs_set() | self._get_protect_lists_set()
|
|
459
|
-
)
|
|
433
|
+
excluded_fields = self._get_excluded_fields()
|
|
460
434
|
if exclude is not None:
|
|
461
435
|
excluded_fields |= exclude
|
|
462
436
|
data = self.dict(exclude=excluded_fields)
|
|
@@ -971,16 +945,13 @@ class ProtectAdoptableDeviceModel(ProtectDeviceModel):
|
|
|
971
945
|
exclude: set[str] | None = None,
|
|
972
946
|
) -> dict[str, Any]:
|
|
973
947
|
data = super().unifi_dict(data=data, exclude=exclude)
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
del data["wifiConnectionState"]
|
|
979
|
-
if (
|
|
980
|
-
"bluetoothConnectionState" in data
|
|
981
|
-
and data["bluetoothConnectionState"] is None
|
|
948
|
+
for key in (
|
|
949
|
+
"wiredConnectionState",
|
|
950
|
+
"wifiConnectionState",
|
|
951
|
+
"bluetoothConnectionState",
|
|
982
952
|
):
|
|
983
|
-
|
|
953
|
+
if key in data and data[key] is None:
|
|
954
|
+
del data[key]
|
|
984
955
|
return data
|
|
985
956
|
|
|
986
957
|
@classmethod
|
|
@@ -8,7 +8,6 @@ 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
|
|
12
11
|
from typing import TYPE_CHECKING, Any
|
|
13
12
|
|
|
14
13
|
from aiohttp.client_exceptions import ServerDisconnectedError
|
|
@@ -220,11 +219,6 @@ class Bootstrap(ProtectBaseObject):
|
|
|
220
219
|
|
|
221
220
|
return super().unifi_dict_to_dict(data)
|
|
222
221
|
|
|
223
|
-
@classmethod
|
|
224
|
-
@cache
|
|
225
|
-
def _unifi_dict_remove_keys(cls) -> set[str]:
|
|
226
|
-
return {"events", "captureWsStats", "macLookup", "idLookup"}
|
|
227
|
-
|
|
228
222
|
def unifi_dict(
|
|
229
223
|
self,
|
|
230
224
|
data: dict[str, Any] | None = None,
|
|
@@ -232,7 +226,7 @@ class Bootstrap(ProtectBaseObject):
|
|
|
232
226
|
) -> dict[str, Any]:
|
|
233
227
|
data = super().unifi_dict(data=data, exclude=exclude)
|
|
234
228
|
|
|
235
|
-
for key in
|
|
229
|
+
for key in ("events", "captureWsStats", "macLookup", "idLookup"):
|
|
236
230
|
if key in data:
|
|
237
231
|
del data[key]
|
|
238
232
|
for model_type in ModelType.bootstrap_models_types_set:
|
|
@@ -1062,27 +1062,21 @@ class Camera(ProtectMotionDeviceModel):
|
|
|
1062
1062
|
]
|
|
1063
1063
|
|
|
1064
1064
|
data = super().unifi_dict(data=data, exclude=exclude)
|
|
1065
|
+
for key in (
|
|
1066
|
+
"lastRingEventId",
|
|
1067
|
+
"lastSmartDetect",
|
|
1068
|
+
"lastSmartAudioDetect",
|
|
1069
|
+
"lastSmartDetectEventId",
|
|
1070
|
+
"lastSmartAudioDetectEventId",
|
|
1071
|
+
"lastSmartDetects",
|
|
1072
|
+
"lastSmartAudioDetects",
|
|
1073
|
+
"lastSmartDetectEventIds",
|
|
1074
|
+
"lastSmartAudioDetectEventIds",
|
|
1075
|
+
"talkbackStream",
|
|
1076
|
+
):
|
|
1077
|
+
if key in data:
|
|
1078
|
+
del data[key]
|
|
1065
1079
|
|
|
1066
|
-
if "lastRingEventId" in data:
|
|
1067
|
-
del data["lastRingEventId"]
|
|
1068
|
-
if "lastSmartDetect" in data:
|
|
1069
|
-
del data["lastSmartDetect"]
|
|
1070
|
-
if "lastSmartAudioDetect" in data:
|
|
1071
|
-
del data["lastSmartAudioDetect"]
|
|
1072
|
-
if "lastSmartDetectEventId" in data:
|
|
1073
|
-
del data["lastSmartDetectEventId"]
|
|
1074
|
-
if "lastSmartAudioDetectEventId" in data:
|
|
1075
|
-
del data["lastSmartAudioDetectEventId"]
|
|
1076
|
-
if "lastSmartDetects" in data:
|
|
1077
|
-
del data["lastSmartDetects"]
|
|
1078
|
-
if "lastSmartAudioDetects" in data:
|
|
1079
|
-
del data["lastSmartAudioDetects"]
|
|
1080
|
-
if "lastSmartDetectEventIds" in data:
|
|
1081
|
-
del data["lastSmartDetectEventIds"]
|
|
1082
|
-
if "lastSmartAudioDetectEventIds" in data:
|
|
1083
|
-
del data["lastSmartAudioDetectEventIds"]
|
|
1084
|
-
if "talkbackStream" in data:
|
|
1085
|
-
del data["talkbackStream"]
|
|
1086
1080
|
if "lcdMessage" in data and data["lcdMessage"] is None:
|
|
1087
1081
|
data["lcdMessage"] = {}
|
|
1088
1082
|
|
|
@@ -2820,18 +2814,15 @@ class Sensor(ProtectAdoptableDeviceModel):
|
|
|
2820
2814
|
exclude: set[str] | None = None,
|
|
2821
2815
|
) -> dict[str, Any]:
|
|
2822
2816
|
data = super().unifi_dict(data=data, exclude=exclude)
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
if "extremeValueDetectedAt" in data:
|
|
2833
|
-
del data["extremeValueDetectedAt"]
|
|
2834
|
-
|
|
2817
|
+
for key in (
|
|
2818
|
+
"lastMotionEventId",
|
|
2819
|
+
"lastContactEventId",
|
|
2820
|
+
"lastValueEventId",
|
|
2821
|
+
"lastAlarmEventId",
|
|
2822
|
+
"extremeValueDetectedAt",
|
|
2823
|
+
):
|
|
2824
|
+
if key in data:
|
|
2825
|
+
del data[key]
|
|
2835
2826
|
return data
|
|
2836
2827
|
|
|
2837
2828
|
@property
|
|
@@ -309,9 +309,9 @@ class Event(ProtectModelWithId):
|
|
|
309
309
|
|
|
310
310
|
@classmethod
|
|
311
311
|
def unifi_dict_to_dict(cls, data: dict[str, Any]) -> dict[str, Any]:
|
|
312
|
-
for key in
|
|
313
|
-
|
|
314
|
-
|
|
312
|
+
for key in ("start", "end", "timestamp", "deletedAt"):
|
|
313
|
+
if key in data:
|
|
314
|
+
data[key] = convert_to_datetime(data[key])
|
|
315
315
|
return super().unifi_dict_to_dict(data)
|
|
316
316
|
|
|
317
317
|
def unifi_dict(
|
|
@@ -47,6 +47,8 @@ class WSSubscriptionMessage:
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
class BaseWSPacketFrame:
|
|
50
|
+
UNPACK_FORMAT = struct.Struct("!bbbbi")
|
|
51
|
+
|
|
50
52
|
data: Any
|
|
51
53
|
position: int = 0
|
|
52
54
|
header: WSPacketFrameHeader | None = None
|
|
@@ -89,7 +91,7 @@ class BaseWSPacketFrame:
|
|
|
89
91
|
i: payload_size
|
|
90
92
|
"""
|
|
91
93
|
header_end = position + WS_HEADER_SIZE
|
|
92
|
-
|
|
94
|
+
payload_size: int
|
|
93
95
|
try:
|
|
94
96
|
(
|
|
95
97
|
packet_type,
|
|
@@ -97,8 +99,7 @@ class BaseWSPacketFrame:
|
|
|
97
99
|
deflated,
|
|
98
100
|
unknown,
|
|
99
101
|
payload_size,
|
|
100
|
-
) =
|
|
101
|
-
"!bbbbi",
|
|
102
|
+
) = BaseWSPacketFrame.UNPACK_FORMAT.unpack(
|
|
102
103
|
data[position:header_end],
|
|
103
104
|
)
|
|
104
105
|
except struct.error as e:
|
|
@@ -117,9 +118,9 @@ class BaseWSPacketFrame:
|
|
|
117
118
|
unknown=unknown,
|
|
118
119
|
payload_size=payload_size,
|
|
119
120
|
)
|
|
120
|
-
frame.length = WS_HEADER_SIZE +
|
|
121
|
-
frame.is_deflated = bool(
|
|
122
|
-
frame_end = header_end +
|
|
121
|
+
frame.length = WS_HEADER_SIZE + payload_size
|
|
122
|
+
frame.is_deflated = bool(deflated)
|
|
123
|
+
frame_end = header_end + payload_size
|
|
123
124
|
frame.set_data_from_binary(data[header_end:frame_end])
|
|
124
125
|
|
|
125
126
|
return frame
|
|
@@ -188,11 +189,10 @@ class WSPacket:
|
|
|
188
189
|
self._raw = data
|
|
189
190
|
|
|
190
191
|
def decode(self) -> None:
|
|
191
|
-
|
|
192
|
-
self.
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
)
|
|
192
|
+
data = self._raw
|
|
193
|
+
self._action_frame = WSRawPacketFrame.from_binary(data)
|
|
194
|
+
length = self._action_frame.length
|
|
195
|
+
self._data_frame = WSRawPacketFrame.from_binary(data, length)
|
|
196
196
|
|
|
197
197
|
@cached_property
|
|
198
198
|
def action_frame(self) -> BaseWSPacketFrame:
|
|
@@ -202,6 +202,7 @@ class WSPacket:
|
|
|
202
202
|
if self._action_frame is None:
|
|
203
203
|
raise WSDecodeError("Packet unexpectedly not decoded")
|
|
204
204
|
|
|
205
|
+
self.__dict__["data_frame"] = self._data_frame
|
|
205
206
|
return self._action_frame
|
|
206
207
|
|
|
207
208
|
@cached_property
|
|
@@ -212,6 +213,7 @@ class WSPacket:
|
|
|
212
213
|
if self._data_frame is None:
|
|
213
214
|
raise WSDecodeError("Packet unexpectedly not decoded")
|
|
214
215
|
|
|
216
|
+
self.__dict__["action_frame"] = self._action_frame
|
|
215
217
|
return self._data_frame
|
|
216
218
|
|
|
217
219
|
@property
|
|
@@ -17,7 +17,7 @@ from copy import deepcopy
|
|
|
17
17
|
from datetime import datetime, timedelta, timezone, tzinfo
|
|
18
18
|
from decimal import Decimal
|
|
19
19
|
from enum import Enum
|
|
20
|
-
from functools import lru_cache
|
|
20
|
+
from functools import cache, lru_cache
|
|
21
21
|
from hashlib import sha224
|
|
22
22
|
from http.cookies import Morsel
|
|
23
23
|
from inspect import isclass
|
|
@@ -96,22 +96,20 @@ IP_TYPES = {
|
|
|
96
96
|
Union[IPv6Address, IPv4Address, None],
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
if sys.version_info[:2] < (3, 11):
|
|
100
|
-
pass
|
|
101
|
-
else:
|
|
102
|
-
pass
|
|
103
|
-
|
|
104
99
|
|
|
105
100
|
def set_debug() -> None:
|
|
106
101
|
"""Sets ENV variable for UFP_DEBUG to on (True)"""
|
|
107
102
|
os.environ[DEBUG_ENV] = str(True)
|
|
103
|
+
is_debug.cache_clear()
|
|
108
104
|
|
|
109
105
|
|
|
110
106
|
def set_no_debug() -> None:
|
|
111
107
|
"""Sets ENV variable for UFP_DEBUG to off (False)"""
|
|
112
108
|
os.environ[DEBUG_ENV] = str(False)
|
|
109
|
+
is_debug.cache_clear()
|
|
113
110
|
|
|
114
111
|
|
|
112
|
+
@cache
|
|
115
113
|
def is_debug() -> bool:
|
|
116
114
|
"""Returns if debug ENV is on (True)"""
|
|
117
115
|
return os.environ.get(DEBUG_ENV) == str(True)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|