uiprotect 1.2.1__tar.gz → 1.3.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.

Files changed (36) hide show
  1. {uiprotect-1.2.1 → uiprotect-1.3.0}/PKG-INFO +1 -1
  2. {uiprotect-1.2.1 → uiprotect-1.3.0}/pyproject.toml +1 -1
  3. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/data/bootstrap.py +58 -64
  4. {uiprotect-1.2.1 → uiprotect-1.3.0}/LICENSE +0 -0
  5. {uiprotect-1.2.1 → uiprotect-1.3.0}/README.md +0 -0
  6. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/__init__.py +0 -0
  7. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/__main__.py +0 -0
  8. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/api.py +0 -0
  9. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/cli/__init__.py +0 -0
  10. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/cli/backup.py +0 -0
  11. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/cli/base.py +0 -0
  12. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/cli/cameras.py +0 -0
  13. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/cli/chimes.py +0 -0
  14. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/cli/doorlocks.py +0 -0
  15. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/cli/events.py +0 -0
  16. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/cli/lights.py +0 -0
  17. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/cli/liveviews.py +0 -0
  18. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/cli/nvr.py +0 -0
  19. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/cli/sensors.py +0 -0
  20. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/cli/viewers.py +0 -0
  21. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/data/__init__.py +0 -0
  22. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/data/base.py +0 -0
  23. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/data/convert.py +0 -0
  24. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/data/devices.py +0 -0
  25. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/data/nvr.py +0 -0
  26. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/data/types.py +0 -0
  27. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/data/user.py +0 -0
  28. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/data/websocket.py +0 -0
  29. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/exceptions.py +0 -0
  30. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/py.typed +0 -0
  31. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/release_cache.json +0 -0
  32. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/stream.py +0 -0
  33. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/test_util/__init__.py +0 -0
  34. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/test_util/anonymize.py +0 -0
  35. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/utils.py +0 -0
  36. {uiprotect-1.2.1 → uiprotect-1.3.0}/src/uiprotect/websocket.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: uiprotect
3
- Version: 1.2.1
3
+ Version: 1.3.0
4
4
  Summary: Python API for Unifi Protect (Unofficial)
5
5
  Home-page: https://github.com/uilibs/uiprotect
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "uiprotect"
3
- version = "1.2.1"
3
+ version = "1.3.0"
4
4
  description = "Python API for Unifi Protect (Unofficial)"
5
5
  authors = ["UI Protect Maintainers <ui@koston.org>"]
6
6
  license = "MIT"
@@ -80,12 +80,9 @@ CAMERA_EVENT_ATTR_MAP: dict[EventType, tuple[str, str]] = {
80
80
  }
81
81
 
82
82
 
83
- def _process_light_event(event: Event) -> None:
84
- if event.light is None:
85
- return
86
-
87
- if _event_is_in_range(event, event.light.last_motion):
88
- event.light.last_motion_event_id = event.id
83
+ def _process_light_event(event: Event, light: Light) -> None:
84
+ if _event_is_in_range(event, light.last_motion):
85
+ light.last_motion_event_id = event.id
89
86
 
90
87
 
91
88
  def _event_is_in_range(event: Event, dt: datetime | None) -> bool:
@@ -95,22 +92,20 @@ def _event_is_in_range(event: Event, dt: datetime | None) -> bool:
95
92
  )
96
93
 
97
94
 
98
- def _process_sensor_event(event: Event) -> None:
99
- if event.sensor is None:
100
- return
95
+ def _process_sensor_event(event: Event, sensor: Sensor) -> None:
101
96
  if event.type is EventType.MOTION_SENSOR:
102
- if _event_is_in_range(event, event.sensor.motion_detected_at):
103
- event.sensor.last_motion_event_id = event.id
97
+ if _event_is_in_range(event, sensor.motion_detected_at):
98
+ sensor.last_motion_event_id = event.id
104
99
  elif event.type in {EventType.SENSOR_CLOSED, EventType.SENSOR_OPENED}:
105
- if _event_is_in_range(event, event.sensor.open_status_changed_at):
106
- event.sensor.last_contact_event_id = event.id
100
+ if _event_is_in_range(event, sensor.open_status_changed_at):
101
+ sensor.last_contact_event_id = event.id
107
102
  elif event.type is EventType.SENSOR_EXTREME_VALUE:
108
- if _event_is_in_range(event, event.sensor.extreme_value_detected_at):
109
- event.sensor.extreme_value_detected_at = event.end
110
- event.sensor.last_value_event_id = event.id
103
+ if _event_is_in_range(event, sensor.extreme_value_detected_at):
104
+ sensor.extreme_value_detected_at = event.end
105
+ sensor.last_value_event_id = event.id
111
106
  elif event.type is EventType.SENSOR_ALARM:
112
- if _event_is_in_range(event, event.sensor.alarm_triggered_at):
113
- event.sensor.last_value_event_id = event.id
107
+ if _event_is_in_range(event, sensor.alarm_triggered_at):
108
+ sensor.last_value_event_id = event.id
114
109
 
115
110
 
116
111
  _CAMERA_SMART_AND_LINE_EVENTS = {
@@ -120,10 +115,7 @@ _CAMERA_SMART_AND_LINE_EVENTS = {
120
115
  _CAMERA_SMART_AUDIO_EVENT = EventType.SMART_AUDIO_DETECT
121
116
 
122
117
 
123
- def _process_camera_event(event: Event) -> None:
124
- if (camera := event.camera) is None:
125
- return
126
-
118
+ def _process_camera_event(event: Event, camera: Camera) -> None:
127
119
  event_type = event.type
128
120
  dt_attr, event_attr = CAMERA_EVENT_ATTR_MAP[event_type]
129
121
  dt: datetime | None = getattr(camera, dt_attr)
@@ -322,12 +314,13 @@ class Bootstrap(ProtectBaseObject):
322
314
  return cast(ProtectAdoptableDeviceModel, devices.get(ref.id))
323
315
 
324
316
  def process_event(self, event: Event) -> None:
325
- if event.type in CAMERA_EVENT_ATTR_MAP and event.camera is not None:
326
- _process_camera_event(event)
327
- elif event.type == EventType.MOTION_LIGHT and event.light is not None:
328
- _process_light_event(event)
329
- elif event.type == EventType.MOTION_SENSOR and event.sensor is not None:
330
- _process_sensor_event(event)
317
+ event_type = event.type
318
+ if event_type in CAMERA_EVENT_ATTR_MAP and (camera := event.camera):
319
+ _process_camera_event(event, camera)
320
+ elif event_type is EventType.MOTION_LIGHT and (light := event.light):
321
+ _process_light_event(event, light)
322
+ elif event_type is EventType.MOTION_SENSOR and (sensor := event.sensor):
323
+ _process_sensor_event(event, sensor)
331
324
 
332
325
  self.events[event.id] = event
333
326
 
@@ -473,47 +466,48 @@ class Bootstrap(ProtectBaseObject):
473
466
  key = f"{model_type}s"
474
467
  devices: dict[str, ProtectModelWithId] = getattr(self, key)
475
468
  action_id: str = action["id"]
476
- if action_id in devices:
477
- if action_id not in devices:
478
- raise ValueError(f"Unknown device update for {model_type}: {action_id}")
479
- obj = devices[action_id]
480
- data = obj.unifi_dict_to_dict(data)
481
- old_obj = obj.copy()
482
- obj = obj.update_from_dict(deepcopy(data))
483
-
484
- if isinstance(obj, Event):
485
- self.process_event(obj)
486
- elif isinstance(obj, Camera):
487
- if "last_ring" in data and obj.last_ring:
488
- is_recent = obj.last_ring + RECENT_EVENT_MAX >= utc_now()
489
- _LOGGER.debug("last_ring for %s (%s)", obj.id, is_recent)
490
- if is_recent:
491
- obj.set_ring_timeout()
492
- elif (
493
- isinstance(obj, Sensor)
494
- and "alarm_triggered_at" in data
495
- and obj.alarm_triggered_at
496
- ):
469
+ if action_id not in devices:
470
+ # ignore updates to events that phase out
471
+ if model_type != _ModelType_Event_value:
472
+ _LOGGER.debug("Unexpected %s: %s", key, action_id)
473
+ return None
474
+
475
+ obj = devices[action_id]
476
+ model = obj.model
477
+ data = obj.unifi_dict_to_dict(data)
478
+ old_obj = obj.copy()
479
+ obj = obj.update_from_dict(deepcopy(data))
480
+
481
+ if model is ModelType.EVENT:
482
+ if TYPE_CHECKING:
483
+ assert isinstance(obj, Event)
484
+ self.process_event(obj)
485
+ elif model is ModelType.CAMERA:
486
+ if TYPE_CHECKING:
487
+ assert isinstance(obj, Camera)
488
+ if "last_ring" in data and obj.last_ring:
489
+ is_recent = obj.last_ring + RECENT_EVENT_MAX >= utc_now()
490
+ _LOGGER.debug("last_ring for %s (%s)", obj.id, is_recent)
491
+ if is_recent:
492
+ obj.set_ring_timeout()
493
+ elif model is ModelType.SENSOR:
494
+ if TYPE_CHECKING:
495
+ assert isinstance(obj, Sensor)
496
+ if "alarm_triggered_at" in data and obj.alarm_triggered_at:
497
497
  is_recent = obj.alarm_triggered_at + RECENT_EVENT_MAX >= utc_now()
498
498
  _LOGGER.debug("alarm_triggered_at for %s (%s)", obj.id, is_recent)
499
499
  if is_recent:
500
500
  obj.set_alarm_timeout()
501
501
 
502
- devices[action_id] = obj
503
-
504
- self._create_stat(packet, data, False)
505
- return WSSubscriptionMessage(
506
- action=WSAction.UPDATE,
507
- new_update_id=self.last_update_id,
508
- changed_data=data,
509
- new_obj=obj,
510
- old_obj=old_obj,
511
- )
512
-
513
- # ignore updates to events that phase out
514
- if model_type != _ModelType_Event_value:
515
- _LOGGER.debug("Unexpected %s: %s", key, action_id)
516
- return None
502
+ devices[action_id] = obj
503
+ self._create_stat(packet, data, False)
504
+ return WSSubscriptionMessage(
505
+ action=WSAction.UPDATE,
506
+ new_update_id=self.last_update_id,
507
+ changed_data=data,
508
+ new_obj=obj,
509
+ old_obj=old_obj,
510
+ )
517
511
 
518
512
  def process_ws_packet(
519
513
  self,
File without changes
File without changes