uiprotect 1.12.0__tar.gz → 1.12.1__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.12.0 → uiprotect-1.12.1}/PKG-INFO +1 -1
  2. {uiprotect-1.12.0 → uiprotect-1.12.1}/pyproject.toml +1 -1
  3. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/data/base.py +7 -2
  4. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/data/bootstrap.py +20 -10
  5. {uiprotect-1.12.0 → uiprotect-1.12.1}/LICENSE +0 -0
  6. {uiprotect-1.12.0 → uiprotect-1.12.1}/README.md +0 -0
  7. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/__init__.py +0 -0
  8. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/__main__.py +0 -0
  9. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/api.py +0 -0
  10. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/cli/__init__.py +0 -0
  11. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/cli/backup.py +0 -0
  12. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/cli/base.py +0 -0
  13. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/cli/cameras.py +0 -0
  14. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/cli/chimes.py +0 -0
  15. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/cli/doorlocks.py +0 -0
  16. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/cli/events.py +0 -0
  17. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/cli/lights.py +0 -0
  18. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/cli/liveviews.py +0 -0
  19. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/cli/nvr.py +0 -0
  20. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/cli/sensors.py +0 -0
  21. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/cli/viewers.py +0 -0
  22. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/data/__init__.py +0 -0
  23. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/data/convert.py +0 -0
  24. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/data/devices.py +0 -0
  25. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/data/nvr.py +0 -0
  26. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/data/types.py +0 -0
  27. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/data/user.py +0 -0
  28. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/data/websocket.py +0 -0
  29. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/exceptions.py +0 -0
  30. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/py.typed +0 -0
  31. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/release_cache.json +0 -0
  32. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/stream.py +0 -0
  33. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/test_util/__init__.py +0 -0
  34. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/test_util/anonymize.py +0 -0
  35. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/utils.py +0 -0
  36. {uiprotect-1.12.0 → uiprotect-1.12.1}/src/uiprotect/websocket.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: uiprotect
3
- Version: 1.12.0
3
+ Version: 1.12.1
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.12.0"
3
+ version = "1.12.1"
4
4
  description = "Python API for Unifi Protect (Unofficial)"
5
5
  authors = ["UI Protect Maintainers <ui@koston.org>"]
6
6
  license = "MIT"
@@ -61,6 +61,9 @@ RECENT_EVENT_MAX = timedelta(seconds=30)
61
61
  EVENT_PING_INTERVAL = timedelta(seconds=3)
62
62
  EVENT_PING_INTERVAL_SECONDS = EVENT_PING_INTERVAL.total_seconds()
63
63
 
64
+ _EMPTY_EVENT_PING_BACK: dict[Any, Any] = {}
65
+
66
+
64
67
  _LOGGER = logging.getLogger(__name__)
65
68
 
66
69
 
@@ -788,7 +791,7 @@ class ProtectModelWithId(ProtectModel):
788
791
 
789
792
  def _emit_message(self, updated: dict[str, Any]) -> None:
790
793
  """Emits fake WS message for ProtectApiClient to process."""
791
- if updated == {}:
794
+ if _is_ping_back := updated is _EMPTY_EVENT_PING_BACK:
792
795
  _LOGGER.debug("Event ping callback started for %s", self.id)
793
796
 
794
797
  if self.model is None:
@@ -817,7 +820,9 @@ class ProtectModelWithId(ProtectModel):
817
820
 
818
821
  message = self._api.bootstrap.process_ws_packet(
819
822
  WSPacket(action_frame.packed + data_frame.packed),
823
+ is_ping_back=_is_ping_back,
820
824
  )
825
+
821
826
  if message is not None:
822
827
  self._api.emit_message(message)
823
828
 
@@ -876,7 +881,7 @@ class ProtectDeviceModel(ProtectModelWithId):
876
881
  self._callback_ping = loop.call_later(
877
882
  EVENT_PING_INTERVAL_SECONDS,
878
883
  self._emit_message,
879
- {},
884
+ _EMPTY_EVENT_PING_BACK,
880
885
  )
881
886
 
882
887
  async def set_name(self, name: str | None) -> None:
@@ -451,7 +451,15 @@ class Bootstrap(ProtectBaseObject):
451
451
  action: dict[str, Any],
452
452
  data: dict[str, Any],
453
453
  ignore_stats: bool,
454
+ is_ping_back: bool,
454
455
  ) -> WSSubscriptionMessage | None:
456
+ """
457
+ Process a device update packet.
458
+
459
+ If is_ping_back is True, the packet is an empty packet
460
+ that was generated internally as a result of an event
461
+ that will expire and result in a state change.
462
+ """
455
463
  remove_keys = (
456
464
  STATS_AND_IGNORE_DEVICE_KEYS if ignore_stats else IGNORE_DEVICE_KEYS
457
465
  )
@@ -462,7 +470,7 @@ class Bootstrap(ProtectBaseObject):
462
470
  if model_type is ModelType.CAMERA and "lastMotion" in data:
463
471
  del data["lastMotion"]
464
472
  # nothing left to process
465
- if not data:
473
+ if not data and not is_ping_back:
466
474
  self._create_stat(packet, None, True)
467
475
  return None
468
476
 
@@ -476,6 +484,12 @@ class Bootstrap(ProtectBaseObject):
476
484
 
477
485
  obj = devices[action_id]
478
486
  data = obj.unifi_dict_to_dict(data)
487
+
488
+ if not data and not is_ping_back:
489
+ # nothing left to process
490
+ self._create_stat(packet, None, True)
491
+ return None
492
+
479
493
  old_obj = obj.copy()
480
494
  obj = obj.update_from_dict(deepcopy(data))
481
495
 
@@ -513,6 +527,7 @@ class Bootstrap(ProtectBaseObject):
513
527
  packet: WSPacket,
514
528
  models: set[ModelType] | None = None,
515
529
  ignore_stats: bool = False,
530
+ is_ping_back: bool = False,
516
531
  ) -> WSSubscriptionMessage | None:
517
532
  """Process a WS packet."""
518
533
  action = packet.action_frame.data
@@ -521,17 +536,16 @@ class Bootstrap(ProtectBaseObject):
521
536
  action = deepcopy(action)
522
537
  data = deepcopy(data)
523
538
 
524
- new_update_id: str = action["newUpdateId"]
539
+ new_update_id: str | None = action["newUpdateId"]
525
540
  if new_update_id is not None:
526
541
  self.last_update_id = new_update_id
527
542
 
528
543
  model_key: str = action["modelKey"]
529
- if model_key not in ModelType.values_set():
544
+ if (model_type := ModelType.from_string(model_key)) is ModelType.UNKNOWN:
530
545
  _LOGGER.debug("Unknown model type: %s", model_key)
531
546
  self._create_stat(packet, None, True)
532
547
  return None
533
548
 
534
- model_type = ModelType.from_string(model_key)
535
549
  if models and model_type not in models:
536
550
  self._create_stat(packet, None, True)
537
551
  return None
@@ -540,7 +554,7 @@ class Bootstrap(ProtectBaseObject):
540
554
  if action_action == "remove":
541
555
  return self._process_remove_packet(model_type, packet)
542
556
 
543
- if not data:
557
+ if not data and not is_ping_back:
544
558
  self._create_stat(packet, None, True)
545
559
  return None
546
560
 
@@ -552,11 +566,7 @@ class Bootstrap(ProtectBaseObject):
552
566
  return self._process_nvr_update(packet, data, ignore_stats)
553
567
  if model_type in ModelType.bootstrap_models_types_and_event_set:
554
568
  return self._process_device_update(
555
- model_type,
556
- packet,
557
- action,
558
- data,
559
- ignore_stats,
569
+ model_type, packet, action, data, ignore_stats, is_ping_back
560
570
  )
561
571
  except (ValidationError, ValueError) as err:
562
572
  self._handle_ws_error(action, err)
File without changes
File without changes