uiprotect 0.12.0__tar.gz → 0.14.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-0.12.0 → uiprotect-0.14.0}/PKG-INFO +1 -1
- {uiprotect-0.12.0 → uiprotect-0.14.0}/pyproject.toml +1 -1
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/data/base.py +4 -4
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/data/bootstrap.py +22 -14
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/data/devices.py +10 -10
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/data/nvr.py +6 -7
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/utils.py +4 -3
- {uiprotect-0.12.0 → uiprotect-0.14.0}/LICENSE +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/README.md +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/__init__.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/__main__.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/api.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/cli/__init__.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/cli/backup.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/cli/base.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/cli/cameras.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/cli/chimes.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/cli/doorlocks.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/cli/events.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/cli/lights.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/cli/liveviews.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/cli/nvr.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/cli/sensors.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/cli/viewers.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/data/__init__.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/data/convert.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/data/types.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/data/user.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/data/websocket.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/exceptions.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/py.typed +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/release_cache.json +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/stream.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/test_util/__init__.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/test_util/anonymize.py +0 -0
- {uiprotect-0.12.0 → uiprotect-0.14.0}/src/uiprotect/websocket.py +0 -0
|
@@ -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"] =
|
|
853
|
+
data["lastSeen"] = convert_to_datetime(data["lastSeen"])
|
|
854
854
|
if "upSince" in data and data["upSince"] is not None:
|
|
855
|
-
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"] =
|
|
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
|
-
|
|
139
|
-
|
|
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(
|
|
142
|
-
setattr(
|
|
143
|
-
if
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
elif
|
|
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
|
-
|
|
153
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
):
|
|
@@ -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"] =
|
|
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"] =
|
|
582
|
+
data["recordingStart"] = convert_to_datetime(data["recordingStart"])
|
|
583
583
|
if "recordingEnd" in data:
|
|
584
|
-
data["recordingEnd"] =
|
|
584
|
+
data["recordingEnd"] = convert_to_datetime(data["recordingEnd"])
|
|
585
585
|
if "recordingStartLQ" in data:
|
|
586
|
-
data["recordingStartLQ"] =
|
|
586
|
+
data["recordingStartLQ"] = convert_to_datetime(data["recordingStartLQ"])
|
|
587
587
|
if "recordingEndLQ" in data:
|
|
588
|
-
data["recordingEndLQ"] =
|
|
588
|
+
data["recordingEndLQ"] = convert_to_datetime(data["recordingEndLQ"])
|
|
589
589
|
if "timelapseStart" in data:
|
|
590
|
-
data["timelapseStart"] =
|
|
590
|
+
data["timelapseStart"] = convert_to_datetime(data["timelapseStart"])
|
|
591
591
|
if "timelapseEnd" in data:
|
|
592
|
-
data["timelapseEnd"] =
|
|
592
|
+
data["timelapseEnd"] = convert_to_datetime(data["timelapseEnd"])
|
|
593
593
|
if "timelapseStartLQ" in data:
|
|
594
|
-
data["timelapseStartLQ"] =
|
|
594
|
+
data["timelapseStartLQ"] = convert_to_datetime(data["timelapseStartLQ"])
|
|
595
595
|
if "timelapseEndLQ" in data:
|
|
596
|
-
data["timelapseEndLQ"] =
|
|
596
|
+
data["timelapseEndLQ"] = convert_to_datetime(data["timelapseEndLQ"])
|
|
597
597
|
|
|
598
598
|
return super().unifi_dict_to_dict(data)
|
|
599
599
|
|
|
@@ -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,
|
|
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"] =
|
|
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] =
|
|
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"] =
|
|
1028
|
+
data["lastUpdateAt"] = convert_to_datetime(data["lastUpdateAt"])
|
|
1029
1029
|
if "lastDeviceFwUpdatesCheckedAt" in data:
|
|
1030
|
-
data["lastDeviceFwUpdatesCheckedAt"] =
|
|
1031
|
-
data
|
|
1032
|
-
"lastDeviceFwUpdatesCheckedAt",
|
|
1030
|
+
data["lastDeviceFwUpdatesCheckedAt"] = convert_to_datetime(
|
|
1031
|
+
data["lastDeviceFwUpdatesCheckedAt"]
|
|
1033
1032
|
)
|
|
1034
1033
|
if (
|
|
1035
1034
|
"recordingRetentionDurationMs" in data
|
|
@@ -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
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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(
|
|
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
|
|
File without changes
|