uiprotect 1.18.1__py3-none-any.whl → 1.19.1__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.

@@ -4,7 +4,6 @@ from __future__ import annotations
4
4
 
5
5
  import asyncio
6
6
  import logging
7
- from collections.abc import Iterable
8
7
  from copy import deepcopy
9
8
  from dataclasses import dataclass
10
9
  from datetime import datetime
@@ -343,28 +342,9 @@ class Bootstrap(ProtectBaseObject):
343
342
 
344
343
  self.events[event.id] = event
345
344
 
346
- def _create_stat(
347
- self,
348
- packet: WSPacket,
349
- keys_set: Iterable[str] | None,
350
- filtered: bool,
351
- ) -> None:
352
- if self.capture_ws_stats:
353
- self._ws_stats.append(
354
- WSStat(
355
- model=packet.action_frame.data["modelKey"],
356
- action=packet.action_frame.data["action"],
357
- keys=list(packet.data_frame.data),
358
- keys_set=[] if keys_set is None else list(keys_set),
359
- size=len(packet.raw),
360
- filtered=filtered,
361
- ),
362
- )
363
-
364
345
  def _process_add_packet(
365
346
  self,
366
347
  model_type: ModelType,
367
- packet: WSPacket,
368
348
  data: dict[str, Any],
369
349
  ) -> WSSubscriptionMessage | None:
370
350
  obj = create_from_unifi_dict(data, api=self._api, model_type=model_type)
@@ -391,33 +371,26 @@ class Bootstrap(ProtectBaseObject):
391
371
  _LOGGER.debug("Unexpected bootstrap model type for add: %s", model_type)
392
372
  return None
393
373
 
394
- updated = obj.dict()
395
-
396
- self._create_stat(packet, updated, False)
397
-
398
374
  return WSSubscriptionMessage(
399
375
  action=WSAction.ADD,
400
376
  new_update_id=self.last_update_id,
401
- changed_data=updated,
377
+ changed_data=obj.dict(),
402
378
  new_obj=obj,
403
379
  )
404
380
 
405
381
  def _process_remove_packet(
406
- self, model_type: ModelType, packet: WSPacket
382
+ self, model_type: ModelType, action: dict[str, Any]
407
383
  ) -> WSSubscriptionMessage | None:
408
384
  devices_key = model_type.devices_key
409
385
  devices: dict[str, ProtectDeviceModel] | None = getattr(self, devices_key, None)
410
-
411
386
  if devices is None:
412
387
  return None
413
388
 
414
- device_id: str = packet.action_frame.data["id"]
389
+ device_id: str = action["id"]
415
390
  self.id_lookup.pop(device_id, None)
416
391
  if (device := devices.pop(device_id, None)) is None:
417
392
  return None
418
393
  self.mac_lookup.pop(normalize_mac(device.mac), None)
419
-
420
- self._create_stat(packet, None, False)
421
394
  return WSSubscriptionMessage(
422
395
  action=WSAction.REMOVE,
423
396
  new_update_id=self.last_update_id,
@@ -427,7 +400,7 @@ class Bootstrap(ProtectBaseObject):
427
400
 
428
401
  def _process_nvr_update(
429
402
  self,
430
- packet: WSPacket,
403
+ action: dict[str, Any],
431
404
  data: dict[str, Any],
432
405
  ignore_stats: bool,
433
406
  ) -> WSSubscriptionMessage | None:
@@ -436,24 +409,20 @@ class Bootstrap(ProtectBaseObject):
436
409
  del data[key]
437
410
  # nothing left to process
438
411
  if not data:
439
- self._create_stat(packet, None, True)
440
412
  return None
441
413
 
442
414
  # for another NVR in stack
443
- nvr_id: str | None = packet.action_frame.data.get("id")
415
+ nvr_id: str | None = action.get("id")
444
416
  if nvr_id and nvr_id != self.nvr.id:
445
- self._create_stat(packet, None, True)
446
417
  return None
447
418
 
448
419
  # nothing left to process
449
420
  if not (data := self.nvr.unifi_dict_to_dict(data)):
450
- self._create_stat(packet, None, True)
451
421
  return None
452
422
 
453
423
  old_nvr = self.nvr.copy()
454
424
  self.nvr = self.nvr.update_from_dict(deepcopy(data))
455
425
 
456
- self._create_stat(packet, data, False)
457
426
  return WSSubscriptionMessage(
458
427
  action=WSAction.UPDATE,
459
428
  new_update_id=self.last_update_id,
@@ -465,7 +434,6 @@ class Bootstrap(ProtectBaseObject):
465
434
  def _process_device_update(
466
435
  self,
467
436
  model_type: ModelType,
468
- packet: WSPacket,
469
437
  action: dict[str, Any],
470
438
  data: dict[str, Any],
471
439
  ignore_stats: bool,
@@ -492,7 +460,6 @@ class Bootstrap(ProtectBaseObject):
492
460
 
493
461
  # nothing left to process
494
462
  if not data and not is_ping_back:
495
- self._create_stat(packet, None, True)
496
463
  return None
497
464
 
498
465
  devices: dict[str, ProtectModelWithId] = getattr(self, model_type.devices_key)
@@ -508,7 +475,6 @@ class Bootstrap(ProtectBaseObject):
508
475
 
509
476
  if not data and not is_ping_back:
510
477
  # nothing left to process
511
- self._create_stat(packet, None, True)
512
478
  return None
513
479
 
514
480
  old_obj = obj.copy()
@@ -534,7 +500,6 @@ class Bootstrap(ProtectBaseObject):
534
500
  _LOGGER.debug("alarm_triggered_at for %s (%s)", obj.id, is_recent)
535
501
 
536
502
  devices[action_id] = obj
537
- self._create_stat(packet, data, False)
538
503
  return WSSubscriptionMessage(
539
504
  action=WSAction.UPDATE,
540
505
  new_update_id=self.last_update_id,
@@ -551,9 +516,10 @@ class Bootstrap(ProtectBaseObject):
551
516
  is_ping_back: bool = False,
552
517
  ) -> WSSubscriptionMessage | None:
553
518
  """Process a WS packet."""
519
+ capture_ws_stats = self.capture_ws_stats
554
520
  action = packet.action_frame.data
555
521
  data = packet.data_frame.data
556
- if self.capture_ws_stats:
522
+ if capture_ws_stats:
557
523
  action = deepcopy(action)
558
524
  data = deepcopy(data)
559
525
 
@@ -561,33 +527,57 @@ class Bootstrap(ProtectBaseObject):
561
527
  if new_update_id is not None:
562
528
  self.last_update_id = new_update_id
563
529
 
530
+ message = self._make_ws_packet_message(
531
+ action, data, models, ignore_stats, is_ping_back
532
+ )
533
+
534
+ if capture_ws_stats:
535
+ self._ws_stats.append(
536
+ WSStat(
537
+ model=packet.action_frame.data["modelKey"],
538
+ action=packet.action_frame.data["action"],
539
+ keys=list(packet.data_frame.data),
540
+ keys_set=[] if message is None else list(message.changed_data),
541
+ size=len(packet.raw),
542
+ filtered=message is None,
543
+ ),
544
+ )
545
+
546
+ return message
547
+
548
+ def _make_ws_packet_message(
549
+ self,
550
+ action: dict[str, Any],
551
+ data: dict[str, Any],
552
+ models: set[ModelType] | None,
553
+ ignore_stats: bool,
554
+ is_ping_back: bool,
555
+ ) -> WSSubscriptionMessage | None:
556
+ """Process a WS packet."""
564
557
  model_key: str = action["modelKey"]
565
558
  if (model_type := ModelType.from_string(model_key)) is ModelType.UNKNOWN:
566
559
  _LOGGER.debug("Unknown model type: %s", model_key)
567
- self._create_stat(packet, None, True)
568
560
  return None
569
561
 
570
562
  if models and model_type not in models:
571
- self._create_stat(packet, None, True)
572
563
  return None
573
564
 
574
565
  action_action: str = action["action"]
575
566
  if action_action == "remove":
576
- return self._process_remove_packet(model_type, packet)
567
+ return self._process_remove_packet(model_type, action)
577
568
 
578
569
  if not data and not is_ping_back:
579
- self._create_stat(packet, None, True)
580
570
  return None
581
571
 
582
572
  try:
583
573
  if action_action == "add":
584
- return self._process_add_packet(model_type, packet, data)
574
+ return self._process_add_packet(model_type, data)
585
575
  if action_action == "update":
586
576
  if model_type is ModelType.NVR:
587
- return self._process_nvr_update(packet, data, ignore_stats)
577
+ return self._process_nvr_update(action, data, ignore_stats)
588
578
  if model_type in ModelType.bootstrap_models_types_and_event_set:
589
579
  return self._process_device_update(
590
- model_type, packet, action, data, ignore_stats, is_ping_back
580
+ model_type, action, data, ignore_stats, is_ping_back
591
581
  )
592
582
  except (ValidationError, ValueError) as err:
593
583
  self._handle_ws_error(action, err)
@@ -595,7 +585,6 @@ class Bootstrap(ProtectBaseObject):
595
585
  _LOGGER.debug(
596
586
  "Unexpected bootstrap model type deviceadoptedfor update: %s", model_key
597
587
  )
598
- self._create_stat(packet, None, True)
599
588
  return None
600
589
 
601
590
  def _handle_ws_error(self, action: dict[str, Any], err: Exception) -> None:
uiprotect/data/devices.py CHANGED
@@ -474,7 +474,9 @@ class SmartDetectSettings(ProtectBaseObject):
474
474
 
475
475
  @classmethod
476
476
  def unifi_dict_to_dict(cls, data: dict[str, Any]) -> dict[str, Any]:
477
- for key in ("objectTypes", "audioTypes", "autoTrackingObjectTypes"):
477
+ if "audioTypes" in data:
478
+ data["audioTypes"] = convert_smart_audio_types(data["audioTypes"])
479
+ for key in ("objectTypes", "autoTrackingObjectTypes"):
478
480
  if key in data:
479
481
  data[key] = convert_smart_types(data[key])
480
482
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: uiprotect
3
- Version: 1.18.1
3
+ Version: 1.19.1
4
4
  Summary: Python API for Unifi Protect (Unofficial)
5
5
  Home-page: https://github.com/uilibs/uiprotect
6
6
  License: MIT
@@ -130,7 +130,7 @@ If you are not okay with the feature being locked behind Remote Access, [let Ubi
130
130
 
131
131
  ## Documentation
132
132
 
133
- [Full documentation for the project](https://uilibs.github.io/uiprotect/).
133
+ [Full documentation for the project](https://uiprotect.readthedocs.io/).
134
134
 
135
135
  ## Requirements
136
136
 
@@ -15,9 +15,9 @@ 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
17
  uiprotect/data/base.py,sha256=q5lpNJ4keAQ4oDjalwg9eL3kaVzEapfwtcTzZZlrN_M,35691
18
- uiprotect/data/bootstrap.py,sha256=GnLBsdgkpeT4P_ND_0mWtK-eAQTYs3FbPQ-84_FvByI,22380
18
+ uiprotect/data/bootstrap.py,sha256=ZieXqE0526F3iRbdJ1pRM6QclSatn_SmecfoOPS3nNg,21922
19
19
  uiprotect/data/convert.py,sha256=8h6Il_DhMkPRDPj9F_rA2UZIlTuchS3BQD24peKpk2A,2185
20
- uiprotect/data/devices.py,sha256=c32wLGkjP-9IiWSlofKqesMVhsyAtrKwsdzwDsncQS0,110387
20
+ uiprotect/data/devices.py,sha256=450T-8qXsFad0xNNnXwm3x53e09NT4dgqlefl7lrc2Q,110485
21
21
  uiprotect/data/nvr.py,sha256=zCEAI-rKLEpp9P63QDvJi0hGRsuv-PWGssgHw1POYeQ,47648
22
22
  uiprotect/data/types.py,sha256=8z8jIoMlfDre7Op1JAN45PLZdAE-4i3gDPSo2uymqu4,17996
23
23
  uiprotect/data/user.py,sha256=Wb-ZWSwIJbyUbfVuENtUYbuW-uftHNDcoMH85dvEjkw,7071
@@ -30,8 +30,8 @@ uiprotect/test_util/__init__.py,sha256=d2g7afa0LSdixQ0kjEDYwafDFME_UlW2LzxpamZ2B
30
30
  uiprotect/test_util/anonymize.py,sha256=f-8ijU-_y9r-uAbhIPn0f0I6hzJpAkvJzc8UpWihObI,8478
31
31
  uiprotect/utils.py,sha256=kVRJwvHP683Sjhi2pnxwCwbaRl_uMQ2qFYSvt9kpfoU,18426
32
32
  uiprotect/websocket.py,sha256=JHI_2EZeRPqPyQopsBZS0dr3tu0HaTiqeLazfBXhW_8,7339
33
- uiprotect-1.18.1.dist-info/LICENSE,sha256=INx18jhdbVXMEiiBANeKEbrbz57ckgzxk5uutmmcxGk,1111
34
- uiprotect-1.18.1.dist-info/METADATA,sha256=YOcBNTMbJa-wwtUfAJ_lP3fIRVIM2FOKfIaAf10sluI,10985
35
- uiprotect-1.18.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
36
- uiprotect-1.18.1.dist-info/entry_points.txt,sha256=J78AUTPrTTxgI3s7SVgrmGqDP7piX2wuuEORzhDdVRA,47
37
- uiprotect-1.18.1.dist-info/RECORD,,
33
+ uiprotect-1.19.1.dist-info/LICENSE,sha256=INx18jhdbVXMEiiBANeKEbrbz57ckgzxk5uutmmcxGk,1111
34
+ uiprotect-1.19.1.dist-info/METADATA,sha256=gqaz3iBcOFl5LGsGh2pIp_6cOd4iV8-cOqN_LBOpo-A,10983
35
+ uiprotect-1.19.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
36
+ uiprotect-1.19.1.dist-info/entry_points.txt,sha256=J78AUTPrTTxgI3s7SVgrmGqDP7piX2wuuEORzhDdVRA,47
37
+ uiprotect-1.19.1.dist-info/RECORD,,